PyMuPDF 1.25.4__tar.gz → 1.25.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. {pymupdf-1.25.4 → pymupdf-1.25.5}/PKG-INFO +1 -1
  2. {pymupdf-1.25.4 → pymupdf-1.25.5}/changes.txt +19 -0
  3. {pymupdf-1.25.4 → pymupdf-1.25.5}/scripts/test.py +12 -1
  4. {pymupdf-1.25.4 → pymupdf-1.25.5}/setup.py +2 -2
  5. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/__init__.py +21 -9
  6. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/extra.i +1 -1
  7. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/table.py +1 -2
  8. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/utils.py +13 -3
  9. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/fitz_old.i +11 -3
  10. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-python.i +1 -1
  11. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/utils.py +9 -1
  12. pymupdf-1.25.5/tests/resources/test_4415.pdf +0 -0
  13. pymupdf-1.25.5/tests/resources/test_4415_out_expected.png +0 -0
  14. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_annots.py +22 -10
  15. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_general.py +16 -1
  16. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_textbox.py +9 -0
  17. {pymupdf-1.25.4 → pymupdf-1.25.5}/COPYING +0 -0
  18. {pymupdf-1.25.4 → pymupdf-1.25.5}/README.md +0 -0
  19. {pymupdf-1.25.4 → pymupdf-1.25.5}/READMEb.md +0 -0
  20. {pymupdf-1.25.4 → pymupdf-1.25.5}/READMEd.md +0 -0
  21. {pymupdf-1.25.4 → pymupdf-1.25.5}/pipcl.py +0 -0
  22. {pymupdf-1.25.4 → pymupdf-1.25.5}/pyproject.toml +0 -0
  23. {pymupdf-1.25.4 → pymupdf-1.25.5}/pytest.ini +0 -0
  24. {pymupdf-1.25.4 → pymupdf-1.25.5}/scripts/gh_release.py +0 -0
  25. {pymupdf-1.25.4 → pymupdf-1.25.5}/scripts/sysinstall.py +0 -0
  26. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/__main__.py +0 -0
  27. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/_apply_pages.py +0 -0
  28. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/_wxcolors.py +0 -0
  29. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/fitz___init__.py +0 -0
  30. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/fitz_table.py +0 -0
  31. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/fitz_utils.py +0 -0
  32. {pymupdf-1.25.4 → pymupdf-1.25.5}/src/pymupdf.py +0 -0
  33. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/__init__.py +0 -0
  34. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/__main__.py +0 -0
  35. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/_config.h +0 -0
  36. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-annot.i +0 -0
  37. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-convert.i +0 -0
  38. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-defines.i +0 -0
  39. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-devices.i +0 -0
  40. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-fields.i +0 -0
  41. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-fileobj.i +0 -0
  42. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-geo-c.i +0 -0
  43. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-geo-py.i +0 -0
  44. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-globals.i +0 -0
  45. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-other.i +0 -0
  46. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-pdfinfo.i +0 -0
  47. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-pixmap.i +0 -0
  48. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-portfolio.i +0 -0
  49. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-select.i +0 -0
  50. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-stext.i +0 -0
  51. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/helper-xobject.i +0 -0
  52. {pymupdf-1.25.4 → pymupdf-1.25.5}/src_classic/version.i +0 -0
  53. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/README.md +0 -0
  54. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/conftest.py +0 -0
  55. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/gentle_compare.py +0 -0
  56. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/001003ED.pdf +0 -0
  57. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/1.pdf +0 -0
  58. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/2.pdf +0 -0
  59. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/2201.00069.pdf +0 -0
  60. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/3.pdf +0 -0
  61. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/4.pdf +0 -0
  62. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/Bezier.epub +0 -0
  63. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/PragmaticaC.otf +0 -0
  64. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/battery-file-22.pdf +0 -0
  65. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/bug1945.pdf +0 -0
  66. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/bug1971.pdf +0 -0
  67. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/chinese-tables.pdf +0 -0
  68. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/chinese-tables.pickle +0 -0
  69. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/circular-toc.pdf +0 -0
  70. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/cms-etc-filled.pdf +0 -0
  71. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/cython.pdf +0 -0
  72. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/cython.pickle +0 -0
  73. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/dotted-gridlines.pdf +0 -0
  74. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/full_toc.txt +0 -0
  75. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/github_sample.pdf +0 -0
  76. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/has-bad-fonts.pdf +0 -0
  77. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/image-file1.pdf +0 -0
  78. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/img-regular.pdf +0 -0
  79. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/img-transparent.pdf +0 -0
  80. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/img-transparent.png +0 -0
  81. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/interfield-calculation.pdf +0 -0
  82. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/joined.pdf +0 -0
  83. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/merge-form1.pdf +0 -0
  84. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/merge-form2.pdf +0 -0
  85. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/metadata.txt +0 -0
  86. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/mupdf_explored.pdf +0 -0
  87. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/nur-ruhig.jpg +0 -0
  88. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/quad-calc-0.pdf +0 -0
  89. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/simple_toc.txt +0 -0
  90. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/small-table.pdf +0 -0
  91. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/strict-yes-no.pdf +0 -0
  92. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/symbol-list.pdf +0 -0
  93. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/symbols.txt +0 -0
  94. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-2333.pdf +0 -0
  95. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-2462.pdf +0 -0
  96. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-2812.pdf +0 -0
  97. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-3143.pdf +0 -0
  98. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-3150.pdf +0 -0
  99. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-3207.pdf +0 -0
  100. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-3591.pdf +0 -0
  101. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-3820.pdf +0 -0
  102. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-4055.pdf +0 -0
  103. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-707448.pdf +0 -0
  104. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-707673.pdf +0 -0
  105. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-E+A.pdf +0 -0
  106. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test-linebreaks.pdf +0 -0
  107. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test2093.pdf +0 -0
  108. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test2182.pdf +0 -0
  109. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test2238.pdf +0 -0
  110. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_1645_expected.pdf +0 -0
  111. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_1824.pdf +0 -0
  112. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2108.pdf +0 -0
  113. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2270.pdf +0 -0
  114. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2533.pdf +0 -0
  115. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2548.pdf +0 -0
  116. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2553-2.pdf +0 -0
  117. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2553.pdf +0 -0
  118. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2596.pdf +0 -0
  119. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2608_expected +0 -0
  120. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2634.pdf +0 -0
  121. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2635.pdf +0 -0
  122. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2645_1.pdf +0 -0
  123. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2645_2.pdf +0 -0
  124. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2645_3.pdf +0 -0
  125. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2710.pdf +0 -0
  126. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2730.pdf +0 -0
  127. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2742.pdf +0 -0
  128. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2788.pdf +0 -0
  129. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2791_content.pdf +0 -0
  130. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2791_coverpage.pdf +0 -0
  131. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2861.pdf +0 -0
  132. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2871.pdf +0 -0
  133. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2885.pdf +0 -0
  134. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2904.pdf +0 -0
  135. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2907.pdf +0 -0
  136. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2954.pdf +0 -0
  137. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2957_1.pdf +0 -0
  138. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2957_2.pdf +0 -0
  139. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2969.pdf +0 -0
  140. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_2979.pdf +0 -0
  141. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3050_expected.png +0 -0
  142. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3058.pdf +0 -0
  143. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3062.pdf +0 -0
  144. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3070.pdf +0 -0
  145. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3072.pdf +0 -0
  146. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3087.pdf +0 -0
  147. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3179.pdf +0 -0
  148. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3186.pdf +0 -0
  149. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3197.pdf +0 -0
  150. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3357.pdf +0 -0
  151. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3362.pdf +0 -0
  152. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3376.pdf +0 -0
  153. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3448.pdf +0 -0
  154. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3448.pdf-expected.png +0 -0
  155. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3450.pdf +0 -0
  156. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3493.epub +0 -0
  157. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3569.pdf +0 -0
  158. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3594.pdf +0 -0
  159. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3615.epub +0 -0
  160. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3624.pdf +0 -0
  161. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3624_expected.png +0 -0
  162. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3650.pdf +0 -0
  163. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3654.docx +0 -0
  164. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3677.pdf +0 -0
  165. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3687-3.epub +0 -0
  166. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3687.epub +0 -0
  167. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3705.pdf +0 -0
  168. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3725.pdf +0 -0
  169. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3727.pdf +0 -0
  170. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3780.pdf +0 -0
  171. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3789.pdf +0 -0
  172. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3842.pdf +0 -0
  173. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3848.pdf +0 -0
  174. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3854.pdf +0 -0
  175. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3854_expected.png +0 -0
  176. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf +0 -0
  177. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.0.png +0 -0
  178. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.1.png +0 -0
  179. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.2.png +0 -0
  180. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.3.png +0 -0
  181. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.4.png +0 -0
  182. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.5.png +0 -0
  183. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.6.png +0 -0
  184. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3863.pdf.pdf.7.png +0 -0
  185. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3886.pdf +0 -0
  186. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3887.pdf +0 -0
  187. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3933.pdf +0 -0
  188. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3950.pdf +0 -0
  189. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_3994.pdf +0 -0
  190. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4004.pdf +0 -0
  191. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4017.pdf +0 -0
  192. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4026.pdf +0 -0
  193. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4034.pdf +0 -0
  194. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4043.pdf +0 -0
  195. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4047.pdf +0 -0
  196. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4079.pdf +0 -0
  197. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4079_after.pdf +0 -0
  198. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4079_after_1.25.pdf +0 -0
  199. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4090.pdf +0 -0
  200. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4125.pdf +0 -0
  201. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4139.pdf +0 -0
  202. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4141.pdf +0 -0
  203. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4147.pdf +0 -0
  204. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4179.pdf +0 -0
  205. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4179_expected.png +0 -0
  206. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4180.pdf +0 -0
  207. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4180_expected.png +0 -0
  208. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4182.pdf +0 -0
  209. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4182_expected.png +0 -0
  210. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4224.pdf +0 -0
  211. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4245.pdf +0 -0
  212. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4245_expected.png +0 -0
  213. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_4263.pdf +0 -0
  214. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_annot_file_info.pdf +0 -0
  215. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_delete_image.pdf +0 -0
  216. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/test_toc_count.pdf +0 -0
  217. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/text-find-ligatures.pdf +0 -0
  218. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/type3font.pdf +0 -0
  219. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/v110-changes.pdf +0 -0
  220. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/resources/widgettest.pdf +0 -0
  221. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/run_compound.py +0 -0
  222. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_2548.py +0 -0
  223. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_2634.py +0 -0
  224. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_2904.py +0 -0
  225. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_2907.py +0 -0
  226. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_4141.py +0 -0
  227. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_badfonts.py +0 -0
  228. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_balance_count.py +0 -0
  229. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_barcode.py +0 -0
  230. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_cluster_drawings.py +0 -0
  231. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_codespell.py +0 -0
  232. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_crypting.py +0 -0
  233. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_docs_samples.py +0 -0
  234. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_drawings.py +0 -0
  235. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_embeddedfiles.py +0 -0
  236. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_extractimage.py +0 -0
  237. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_flake8.py +0 -0
  238. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_font.py +0 -0
  239. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_geometry.py +0 -0
  240. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_imagebbox.py +0 -0
  241. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_imagemasks.py +0 -0
  242. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_import.py +0 -0
  243. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_insertimage.py +0 -0
  244. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_insertpdf.py +0 -0
  245. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_linebreaks.py +0 -0
  246. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_linequad.py +0 -0
  247. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_memory.py +0 -0
  248. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_metadata.py +0 -0
  249. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_mupdf_regressions.py +0 -0
  250. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_named_links.py +0 -0
  251. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_nonpdf.py +0 -0
  252. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_object_manipulation.py +0 -0
  253. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_objectstreams.py +0 -0
  254. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_optional_content.py +0 -0
  255. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_page_links.py +0 -0
  256. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_pagedelete.py +0 -0
  257. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_pagelabels.py +0 -0
  258. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_pixmap.py +0 -0
  259. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_pylint.py +0 -0
  260. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_remove-rotation.py +0 -0
  261. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_rtl.py +0 -0
  262. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_showpdfpage.py +0 -0
  263. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_spikes.py +0 -0
  264. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_story.py +0 -0
  265. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_tables.py +0 -0
  266. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_tesseract.py +0 -0
  267. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_textextract.py +0 -0
  268. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_textsearch.py +0 -0
  269. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_toc.py +0 -0
  270. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_widgets.py +0 -0
  271. {pymupdf-1.25.4 → pymupdf-1.25.5}/tests/test_word_delimiters.py +0 -0
  272. {pymupdf-1.25.4 → pymupdf-1.25.5}/valgrind.supp +0 -0
  273. {pymupdf-1.25.4 → pymupdf-1.25.5}/wdev.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyMuPDF
3
- Version: 1.25.4
3
+ Version: 1.25.5
4
4
  Summary: A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.
5
5
  Description-Content-Type: text/markdown
6
6
  Author: Artifex
@@ -2,8 +2,27 @@ Change Log
2
2
  ==========
3
3
 
4
4
 
5
+ **Changes in version 1.25.5 (2025-03-31)**
6
+
7
+ * Fixed issues:
8
+
9
+ * **Fixed** `4372 <https://github.com/pymupdf/PyMuPDF/issues/4372>`_: Text insertion fails due to missing /Resources object
10
+ * **Fixed** `4400 <https://github.com/pymupdf/PyMuPDF/issues/4400>`_: Infinite loop in fill_textbox
11
+ * **Fixed** `4403 <https://github.com/pymupdf/PyMuPDF/issues/4403>`_: Unable to get_text() - layer/clip nesting too deep
12
+ * **Fixed** `4415 <https://github.com/pymupdf/PyMuPDF/issues/4415>`_: PDF page is mirrored, origin is at bottom-left
13
+
14
+ * Other:
15
+
16
+ * Use MuPDF-1.25.6.
17
+ * Fixed MuPDF SEGV on MacOS with particular fonts.
18
+ * Fixed `Annot.get_textpage()`'s `clip` arg.
19
+ * Fixed Python-3.14 (pre-release) build error.
20
+
21
+
5
22
  **Changes in version 1.25.4 (2025-03-14)**
6
23
 
24
+ * Use MuPDF-1.25.5.
25
+
7
26
  * Fixed issues:
8
27
 
9
28
  * **Fixed** `4079 <https://github.com/pymupdf/PyMuPDF/issues/4079>`_: Unexpected result for apply_redactions()
@@ -94,6 +94,8 @@ Options:
94
94
  Whether to rebuild mupdf when we build PyMuPDF. Default is 1.
95
95
  --gdb 0|1
96
96
  Run tests under gdb. Requires user interaction.
97
+ --pytest-prefix <command>
98
+ Use specified prefix when running pytest. E.g. `gdb --args`.
97
99
  --pybind 0|1
98
100
  Experimental, for investigating
99
101
  https://github.com/pymupdf/PyMuPDF/issues/3869. Runs run basic code
@@ -185,6 +187,7 @@ def main(argv):
185
187
  implementations = 'r'
186
188
  test_names = list()
187
189
  venv = 2
190
+ pytest_prefix = None
188
191
  pybind = False
189
192
  pytest_options = None
190
193
  timeout = None
@@ -222,7 +225,7 @@ def main(argv):
222
225
  implementations = next(args)
223
226
  elif arg in ('--mupdf', '-m'):
224
227
  mupdf = next(args)
225
- if not mupdf.startswith('git:') and mupdf != '-':
228
+ if not mupdf.startswith('git:') and '://' not in mupdf and mupdf != '-':
226
229
  assert os.path.isdir(mupdf), f'Not a directory: {mupdf=}.'
227
230
  mupdf = os.path.abspath(mupdf)
228
231
  os.environ['PYMUPDF_SETUP_MUPDF_BUILD'] = mupdf
@@ -236,6 +239,8 @@ def main(argv):
236
239
  value = next(args)
237
240
  assert value in ('0', '1'), f'`-s` must be followed by `0` or `1`, not {value=}.'
238
241
  os.environ['PYMUPDF_SETUP_PY_LIMITED_API'] = value
242
+ elif arg == '--pytest-prefix':
243
+ pytest_prefix = next(args)
239
244
  elif arg == '--pybind':
240
245
  pybind = int(next(args))
241
246
  elif arg == '--system-site-packages':
@@ -312,6 +317,7 @@ def main(argv):
312
317
  pytest_options=pytest_options,
313
318
  timeout=timeout,
314
319
  gdb=gdb,
320
+ pytest_prefix=pytest_prefix,
315
321
  test_fitz=test_fitz,
316
322
  pytest_k=pytest_k,
317
323
  pybind=pybind,
@@ -603,6 +609,7 @@ def test(
603
609
  pytest_options=None,
604
610
  timeout=None,
605
611
  gdb=False,
612
+ pytest_prefix=None,
606
613
  test_fitz=True,
607
614
  pytest_k=None,
608
615
  pybind=False,
@@ -624,6 +631,8 @@ def test(
624
631
  See top-level option `-p`.
625
632
  gdb:
626
633
  See top-level option `--gdb`.
634
+ pytest_prefix:
635
+ See top-level option `--pytest-prefix`.
627
636
  test_fitz:
628
637
  See top-level option `-f`.
629
638
  '''
@@ -732,6 +741,8 @@ def test(
732
741
  )
733
742
  elif gdb:
734
743
  command = f'{python} {pymupdf_dir_rel}/tests/run_compound.py{run_compound_args} gdb --args {python} -m pytest {pytest_options} {pytest_arg}'
744
+ elif pytest_prefix:
745
+ command = f'{python} {pymupdf_dir_rel}/tests/run_compound.py{run_compound_args} {pytest_prefix} {python} -m pytest {pytest_options} {pytest_arg}'
735
746
  elif platform.system() == 'Windows':
736
747
  # `python -m pytest` doesn't seem to work.
737
748
  command = f'{python} {pymupdf_dir_rel}/tests/run_compound.py{run_compound_args} pytest {pytest_options} {pytest_arg}'
@@ -1242,7 +1242,7 @@ classifier = [
1242
1242
  #
1243
1243
 
1244
1244
  # PyMuPDF version.
1245
- version_p = '1.25.4'
1245
+ version_p = '1.25.5'
1246
1246
 
1247
1247
  # PyMuPDFb version. This is the PyMuPDF version whose PyMuPDFb wheels we will
1248
1248
  # (re)use if generating separate PyMuPDFb wheels. Though as of PyMuPDF-1.24.11
@@ -1250,7 +1250,7 @@ version_p = '1.25.4'
1250
1250
  #
1251
1251
  version_b = '1.25.3'
1252
1252
 
1253
- version_mupdf = '1.25.5'
1253
+ version_mupdf = '1.25.6'
1254
1254
 
1255
1255
  if os.path.exists(f'{g_root}/{g_pymupdfb_sdist_marker}'):
1256
1256
 
@@ -373,9 +373,9 @@ def _int_rc(text):
373
373
 
374
374
  # Basic version information.
375
375
  #
376
- pymupdf_version = "1.25.4"
376
+ pymupdf_version = "1.25.5"
377
377
  mupdf_version = mupdf.FZ_VERSION
378
- pymupdf_date = "2025-03-14 00:00:01"
378
+ pymupdf_date = "2025-03-31 00:00:01"
379
379
 
380
380
  # Versions as tuples; useful when comparing versions.
381
381
  #
@@ -419,8 +419,15 @@ def _format_g(value, *, fmt='%g'):
419
419
 
420
420
  format_g = _format_g
421
421
 
422
+ # ByteString is gone from typing in 3.14.
423
+ # collections.abc.Buffer available from 3.12 only
424
+ try:
425
+ ByteString = typing.ByteString
426
+ except AttributeError:
427
+ ByteString = bytes | bytearray | memoryview
428
+
422
429
  # Names required by class method typing annotations.
423
- OptBytes = typing.Optional[typing.ByteString]
430
+ OptBytes = typing.Optional[ByteString]
424
431
  OptDict = typing.Optional[dict]
425
432
  OptFloat = typing.Optional[float]
426
433
  OptInt = typing.Union[int, None]
@@ -1022,8 +1029,11 @@ class Annot:
1022
1029
  def get_textpage(self, clip=None, flags=0):
1023
1030
  """Make annotation TextPage."""
1024
1031
  CheckParent(self)
1025
- options = mupdf.FzStextOptions()
1026
- options.flags = flags
1032
+ options = mupdf.FzStextOptions(flags)
1033
+ if clip:
1034
+ clip2 = JM_rect_from_py(clip)
1035
+ options.clip = clip2.internal()
1036
+ options.flags |= mupdf.FZ_STEXT_CLIP_RECT
1027
1037
  annot = self.this
1028
1038
  stextpage = mupdf.FzStextPage(annot, options)
1029
1039
  ret = TextPage(stextpage)
@@ -3979,7 +3989,7 @@ class Document:
3979
3989
 
3980
3990
  def embfile_add(self,
3981
3991
  name: str,
3982
- buffer_: typing.ByteString,
3992
+ buffer_: ByteString,
3983
3993
  filename: OptStr =None,
3984
3994
  ufilename: OptStr =None,
3985
3995
  desc: OptStr =None,
@@ -8096,7 +8106,9 @@ class Page:
8096
8106
 
8097
8107
  value = JM_insert_font(pdf, bfname, fontfile,fontbuffer, set_simple, idx, wmode, serif, encoding, ordering)
8098
8108
  # get the objects /Resources, /Resources/Font
8099
- resources = mupdf.pdf_dict_get_inheritable( page.obj(), PDF_NAME('Resources'))
8109
+ resources = mupdf.pdf_dict_get_inheritable(page.obj(), PDF_NAME('Resources'))
8110
+ if not resources.pdf_is_dict():
8111
+ resources = mupdf.pdf_dict_put_dict(page.obj(), PDF_NAME("Resources"), 5)
8100
8112
  fonts = mupdf.pdf_dict_get(resources, PDF_NAME('Font'))
8101
8113
  if not fonts.m_internal: # page has no fonts yet
8102
8114
  fonts = mupdf.pdf_new_dict(pdf, 5)
@@ -8282,7 +8294,7 @@ class Page:
8282
8294
  def add_file_annot(
8283
8295
  self,
8284
8296
  point: point_like,
8285
- buffer_: typing.ByteString,
8297
+ buffer_: ByteString,
8286
8298
  filename: str,
8287
8299
  ufilename: OptStr =None,
8288
8300
  desc: OptStr =None,
@@ -18379,7 +18391,7 @@ def get_text_length(text: str, fontname: str ="helv", fontsize: float =11, encod
18379
18391
  raise ValueError("Font '%s' is unsupported" % fontname)
18380
18392
 
18381
18393
 
18382
- def image_profile(img: typing.ByteString) -> dict:
18394
+ def image_profile(img: ByteString) -> dict:
18383
18395
  """ Return basic properties of an image.
18384
18396
 
18385
18397
  Args:
@@ -4113,7 +4113,7 @@ PyObject* ll_JM_color_count(fz_pixmap *pm, PyObject *clip)
4113
4113
  unsigned char* s = pm->samples + stride * (irect.y0 - pm->y) + n * (irect.x0 - pm->x);
4114
4114
  // Cache previous pixel.
4115
4115
  char oldpix[10];
4116
- assert(n < = size(oldpix));
4116
+ assert(n <= sizeof(oldpix));
4117
4117
  memcpy(oldpix, s, n);
4118
4118
  long cnt = 0;
4119
4119
  for (size_t i = 0; i < height; i++)
@@ -1883,7 +1883,7 @@ page information themselves.
1883
1883
  # -----------------------------------------------------------------------------
1884
1884
  def make_chars(page, clip=None):
1885
1885
  """Extract text as "rawdict" to fill CHARS."""
1886
- global CHARS, TEXTPAGE
1886
+ global TEXTPAGE
1887
1887
  page_number = page.number + 1
1888
1888
  page_height = page.rect.height
1889
1889
  ctm = page.transformation_matrix
@@ -1943,7 +1943,6 @@ def make_chars(page, clip=None):
1943
1943
  # else to lines.
1944
1944
  # ------------------------------------------------------------------------
1945
1945
  def make_edges(page, clip=None, tset=None, add_lines=None):
1946
- global EDGES
1947
1946
  snap_x = tset.snap_x_tolerance
1948
1947
  snap_y = tset.snap_y_tolerance
1949
1948
  min_length = tset.edge_min_length
@@ -29,12 +29,21 @@ point_like = "point_like"
29
29
  rect_like = "rect_like"
30
30
  matrix_like = "matrix_like"
31
31
  quad_like = "quad_like"
32
+
33
+ # ByteString is gone from typing in 3.14.
34
+ # collections.abc.Buffer available from 3.12 only
35
+ try:
36
+ ByteString = typing.ByteString
37
+ except AttributeError:
38
+ # pylint: disable=unsupported-binary-operation
39
+ ByteString = bytes | bytearray | memoryview
40
+
32
41
  AnyType = typing.Any
33
42
  OptInt = typing.Union[int, None]
34
43
  OptFloat = typing.Optional[float]
35
44
  OptStr = typing.Optional[str]
36
45
  OptDict = typing.Optional[dict]
37
- OptBytes = typing.Optional[typing.ByteString]
46
+ OptBytes = typing.Optional[ByteString]
38
47
  OptSeq = typing.Optional[typing.Sequence]
39
48
 
40
49
  """
@@ -4601,12 +4610,12 @@ def fill_textbox(
4601
4610
  words = line.split(" ") # the words in the line
4602
4611
 
4603
4612
  # cut in parts any words that are longer than rect width
4604
- words, word_lengths = norm_words(std_width, words)
4613
+ words, word_lengths = norm_words(width, words)
4605
4614
 
4606
4615
  n = len(words)
4607
4616
  while True:
4608
4617
  line0 = " ".join(words[:n])
4609
- wl = sum(word_lengths[:n]) + space_len * (len(word_lengths[:n]) - 1)
4618
+ wl = sum(word_lengths[:n]) + space_len * (n - 1)
4610
4619
  if wl <= width:
4611
4620
  new_lines.append((line0, wl))
4612
4621
  words = words[n:]
@@ -4618,6 +4627,7 @@ def fill_textbox(
4618
4627
 
4619
4628
  if len(words) == 0:
4620
4629
  break
4630
+ assert n
4621
4631
 
4622
4632
  # -------------------------------------------------------------------------
4623
4633
  # List of lines created. Each item is (text, tl), where 'tl' is the PDF
@@ -321,12 +321,20 @@ point_like = "point_like"
321
321
  rect_like = "rect_like"
322
322
  matrix_like = "matrix_like"
323
323
  quad_like = "quad_like"
324
+
325
+ # ByteString is gone from typing in 3.14.
326
+ # collections.abc.Buffer available from 3.12 only
327
+ try:
328
+ ByteString = typing.ByteString
329
+ except AttributeError:
330
+ ByteString = bytes | bytearray | memoryview
331
+
324
332
  AnyType = typing.Any
325
333
  OptInt = typing.Union[int, None]
326
334
  OptFloat = typing.Optional[float]
327
335
  OptStr = typing.Optional[str]
328
336
  OptDict = typing.Optional[dict]
329
- OptBytes = typing.Optional[typing.ByteString]
337
+ OptBytes = typing.Optional[ByteString]
330
338
  OptSeq = typing.Optional[typing.Sequence]
331
339
 
332
340
  try:
@@ -1342,7 +1350,7 @@ struct Document
1342
1350
  self.xref_set_key(xref, "Params/ModDate", get_pdf_str(date))
1343
1351
  return xref
1344
1352
 
1345
- def embfile_add(self, name: str, buffer: typing.ByteString,
1353
+ def embfile_add(self, name: str, buffer: ByteString,
1346
1354
  filename: OptStr =None,
1347
1355
  ufilename: OptStr =None,
1348
1356
  desc: OptStr =None,) -> None:
@@ -5964,7 +5972,7 @@ struct Page {
5964
5972
 
5965
5973
 
5966
5974
  def add_file_annot(self, point: point_like,
5967
- buffer: typing.ByteString,
5975
+ buffer: ByteString,
5968
5976
  filename: str,
5969
5977
  ufilename: OptStr =None,
5970
5978
  desc: OptStr =None,
@@ -1245,7 +1245,7 @@ def planish_line(p1: point_like, p2: point_like) -> Matrix:
1245
1245
  return Matrix(util_hor_matrix(p1, p2))
1246
1246
 
1247
1247
 
1248
- def image_profile(img: typing.ByteString) -> dict:
1248
+ def image_profile(img: ByteString) -> dict:
1249
1249
  """ Return basic properties of an image.
1250
1250
 
1251
1251
  Args:
@@ -23,12 +23,20 @@ point_like = "point_like"
23
23
  rect_like = "rect_like"
24
24
  matrix_like = "matrix_like"
25
25
  quad_like = "quad_like"
26
+
27
+ # ByteString is gone from typing in 3.14.
28
+ # collections.abc.Buffer available from 3.12 only
29
+ try:
30
+ ByteString = typing.ByteString
31
+ except AttributeError:
32
+ ByteString = bytes | bytearray | memoryview
33
+
26
34
  AnyType = typing.Any
27
35
  OptInt = typing.Union[int, None]
28
36
  OptFloat = typing.Optional[float]
29
37
  OptStr = typing.Optional[str]
30
38
  OptDict = typing.Optional[dict]
31
- OptBytes = typing.Optional[typing.ByteString]
39
+ OptBytes = typing.Optional[ByteString]
32
40
  OptSeq = typing.Optional[typing.Sequence]
33
41
 
34
42
  """
@@ -276,6 +276,7 @@ def test_2270():
276
276
  for page_number, page in enumerate(document):
277
277
  for textBox in page.annots(types=(pymupdf.PDF_ANNOT_FREE_TEXT,pymupdf.PDF_ANNOT_TEXT)):
278
278
  print("textBox.type :", textBox.type)
279
+ print(f"{textBox.rect=}")
279
280
  print("textBox.get_text('words') : ", textBox.get_text('words'))
280
281
  print("textBox.get_text('text') : ", textBox.get_text('text'))
281
282
  print("textBox.get_textbox(textBox.rect) : ", textBox.get_textbox(textBox.rect))
@@ -286,16 +287,27 @@ def test_2270():
286
287
  assert textBox.get_textbox(textBox.rect) == 'abc123'
287
288
  assert textBox.info['content'] == 'abc123'
288
289
 
289
- if hasattr(pymupdf, 'mupdf'):
290
- # Additional check that Annot.get_textpage() returns a
291
- # TextPage that works with page.get_text() - prior to
292
- # 2024-01-30 the TextPage had no `.parent` member.
293
- textpage = textBox.get_textpage()
294
- text = page.get_text()
295
- print(f'{text=}')
296
- text = page.get_text(textpage=textpage)
297
- print(f'{text=}')
298
- print(f'{getattr(textpage, "parent")=}')
290
+ # Additional check that Annot.get_textpage() returns a
291
+ # TextPage that works with page.get_text() - prior to
292
+ # 2024-01-30 the TextPage had no `.parent` member.
293
+ textpage = textBox.get_textpage()
294
+ text = page.get_text()
295
+ print(f'{text=}')
296
+ text = page.get_text(textpage=textpage)
297
+ print(f'{text=}')
298
+ print(f'{getattr(textpage, "parent")=}')
299
+
300
+ if pymupdf.mupdf_version_tuple >= (1, 26):
301
+ # Check Annotation.get_textpage()'s <clip> arg.
302
+ clip = textBox.rect
303
+ clip.x1 = clip.x0 + (clip.x1 - clip.x0) / 3
304
+ textpage2 = textBox.get_textpage(clip=clip)
305
+ text = textpage2.extractText()
306
+ print(f'With {clip=}: {text=}')
307
+ assert text == 'ab\n'
308
+ else:
309
+ assert not hasattr(pymupdf.mupdf, 'FZ_STEXT_CLIP_RECT')
310
+
299
311
 
300
312
  def test_2934_add_redact_annot():
301
313
  '''
@@ -1669,4 +1669,19 @@ def test_3886():
1669
1669
  rms_0 = gentle_compare.pixmaps_rms(pixmap, pixmap_clean0)
1670
1670
  rms_1 = gentle_compare.pixmaps_rms(pixmap, pixmap_clean1)
1671
1671
  print(f'test_3886(): {rms_0=} {rms_1=}')
1672
-
1672
+
1673
+ def test_4415():
1674
+ path = os.path.normpath(f'{__file__}/../../tests/resources/test_4415.pdf')
1675
+ path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4415_out.png')
1676
+ path_out_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4415_out_expected.png')
1677
+ with pymupdf.open(path) as document:
1678
+ page = document[0]
1679
+ rot = page.rotation
1680
+ orig = pymupdf.Point(100, 100) # apparent insertion point
1681
+ text = 'Text at Top-Left'
1682
+ mrot = page.derotation_matrix # matrix annihilating page rotation
1683
+ page.insert_text(orig * mrot, text, fontsize=60, rotate=rot)
1684
+ pixmap = page.get_pixmap()
1685
+ pixmap.save(path_out)
1686
+ rms = gentle_compare.pixmaps_rms(path_out_expected, path_out)
1687
+ assert rms == 0, f'{rms=}'
@@ -280,3 +280,12 @@ def test_3916():
280
280
  page = doc.new_page()
281
281
  spare_height, scale = page.insert_htmlbox(rect, "Hello, World!", scale_low=0.5)
282
282
  assert spare_height == -1
283
+
284
+
285
+ def test_4400():
286
+ with pymupdf.open() as document:
287
+ page = document.new_page()
288
+ writer = pymupdf.TextWriter(page.rect)
289
+ text = '111111111'
290
+ print(f'Calling writer.fill_textbox().', flush=1)
291
+ writer.fill_textbox(rect=pymupdf.Rect(0, 0, 100, 20), pos=(80, 0), text=text, fontsize=8)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes