wxPython 4.3.2__cp315-cp315-win_amd64.whl

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 (472) hide show
  1. wx/WebView2Loader.dll +0 -0
  2. wx/__init__.py +22 -0
  3. wx/__init__.pyi +10 -0
  4. wx/__version__.py +9 -0
  5. wx/__version__.pyi +15 -0
  6. wx/_adv.cp315-win_amd64.pyd +0 -0
  7. wx/_aui.cp315-win_amd64.pyd +0 -0
  8. wx/_core.cp315-win_amd64.pyd +0 -0
  9. wx/_dataview.cp315-win_amd64.pyd +0 -0
  10. wx/_glcanvas.cp315-win_amd64.pyd +0 -0
  11. wx/_grid.cp315-win_amd64.pyd +0 -0
  12. wx/_html.cp315-win_amd64.pyd +0 -0
  13. wx/_html2.cp315-win_amd64.pyd +0 -0
  14. wx/_media.cp315-win_amd64.pyd +0 -0
  15. wx/_msw.cp315-win_amd64.pyd +0 -0
  16. wx/_propgrid.cp315-win_amd64.pyd +0 -0
  17. wx/_ribbon.cp315-win_amd64.pyd +0 -0
  18. wx/_richtext.cp315-win_amd64.pyd +0 -0
  19. wx/_stc.cp315-win_amd64.pyd +0 -0
  20. wx/_xml.cp315-win_amd64.pyd +0 -0
  21. wx/_xrc.cp315-win_amd64.pyd +0 -0
  22. wx/adv.py +127 -0
  23. wx/adv.pyi +5931 -0
  24. wx/aui.py +70 -0
  25. wx/aui.pyi +4805 -0
  26. wx/core.py +3417 -0
  27. wx/core.pyi +62949 -0
  28. wx/dataview.py +176 -0
  29. wx/dataview.pyi +3828 -0
  30. wx/gizmos.py +18 -0
  31. wx/glcanvas.py +13 -0
  32. wx/glcanvas.pyi +544 -0
  33. wx/grid.py +237 -0
  34. wx/grid.pyi +5678 -0
  35. wx/html.py +38 -0
  36. wx/html.pyi +3283 -0
  37. wx/html2.py +46 -0
  38. wx/html2.pyi +1301 -0
  39. wx/include/wxPython/sip.h +1938 -0
  40. wx/include/wxPython/wxpy_api.h +418 -0
  41. wx/lib/CDate.py +201 -0
  42. wx/lib/ClickableHtmlWindow.py +57 -0
  43. wx/lib/__init__.py +0 -0
  44. wx/lib/activex.py +178 -0
  45. wx/lib/activexwrapper.py +153 -0
  46. wx/lib/agw/__init__.py +128 -0
  47. wx/lib/agw/advancedsplash.py +563 -0
  48. wx/lib/agw/aquabutton.py +1127 -0
  49. wx/lib/agw/artmanager.py +2110 -0
  50. wx/lib/agw/aui/__init__.py +295 -0
  51. wx/lib/agw/aui/aui_constants.py +2616 -0
  52. wx/lib/agw/aui/aui_switcherdialog.py +1232 -0
  53. wx/lib/agw/aui/aui_utilities.py +648 -0
  54. wx/lib/agw/aui/auibar.py +4045 -0
  55. wx/lib/agw/aui/auibook.py +6288 -0
  56. wx/lib/agw/aui/dockart.py +1198 -0
  57. wx/lib/agw/aui/framemanager.py +10485 -0
  58. wx/lib/agw/aui/tabart.py +2749 -0
  59. wx/lib/agw/aui/tabmdi.py +679 -0
  60. wx/lib/agw/balloontip.py +1157 -0
  61. wx/lib/agw/buttonpanel.py +2787 -0
  62. wx/lib/agw/cubecolourdialog.py +3529 -0
  63. wx/lib/agw/customtreectrl.py +9908 -0
  64. wx/lib/agw/data/ShortcutEditor_1.png +0 -0
  65. wx/lib/agw/data/ShortcutEditor_1_thumb.png +0 -0
  66. wx/lib/agw/data/ShortcutEditor_2.png +0 -0
  67. wx/lib/agw/data/ShortcutEditor_2_thumb.png +0 -0
  68. wx/lib/agw/data/ShortcutEditor_3.png +0 -0
  69. wx/lib/agw/data/ShortcutEditor_3_thumb.png +0 -0
  70. wx/lib/agw/data/ShortcutEditor_4.png +0 -0
  71. wx/lib/agw/data/ShortcutEditor_4_thumb.png +0 -0
  72. wx/lib/agw/data/default_help_text.html +105 -0
  73. wx/lib/agw/flatmenu.py +7392 -0
  74. wx/lib/agw/flatnotebook.py +6669 -0
  75. wx/lib/agw/floatspin.py +1820 -0
  76. wx/lib/agw/fmcustomizedlg.py +535 -0
  77. wx/lib/agw/fmresources.py +407 -0
  78. wx/lib/agw/foldpanelbar.py +2282 -0
  79. wx/lib/agw/fourwaysplitter.py +1130 -0
  80. wx/lib/agw/genericmessagedialog.py +1549 -0
  81. wx/lib/agw/gradientbutton.py +731 -0
  82. wx/lib/agw/hyperlink.py +664 -0
  83. wx/lib/agw/hypertreelist.py +5756 -0
  84. wx/lib/agw/infobar.py +885 -0
  85. wx/lib/agw/knobctrl.py +944 -0
  86. wx/lib/agw/labelbook.py +3028 -0
  87. wx/lib/agw/multidirdialog.py +581 -0
  88. wx/lib/agw/peakmeter.py +1028 -0
  89. wx/lib/agw/persist/__init__.py +188 -0
  90. wx/lib/agw/persist/persist_constants.py +283 -0
  91. wx/lib/agw/persist/persist_handlers.py +2614 -0
  92. wx/lib/agw/persist/persistencemanager.py +863 -0
  93. wx/lib/agw/piectrl.py +1082 -0
  94. wx/lib/agw/pybusyinfo.py +399 -0
  95. wx/lib/agw/pycollapsiblepane.py +940 -0
  96. wx/lib/agw/pygauge.py +570 -0
  97. wx/lib/agw/pyprogress.py +916 -0
  98. wx/lib/agw/ribbon/__init__.py +198 -0
  99. wx/lib/agw/ribbon/art.py +219 -0
  100. wx/lib/agw/ribbon/art_aui.py +1283 -0
  101. wx/lib/agw/ribbon/art_default.py +81 -0
  102. wx/lib/agw/ribbon/art_internal.py +248 -0
  103. wx/lib/agw/ribbon/art_msw.py +2735 -0
  104. wx/lib/agw/ribbon/art_osx.py +52 -0
  105. wx/lib/agw/ribbon/bar.py +1259 -0
  106. wx/lib/agw/ribbon/buttonbar.py +1317 -0
  107. wx/lib/agw/ribbon/control.py +205 -0
  108. wx/lib/agw/ribbon/gallery.py +973 -0
  109. wx/lib/agw/ribbon/page.py +946 -0
  110. wx/lib/agw/ribbon/panel.py +1170 -0
  111. wx/lib/agw/ribbon/toolbar.py +1441 -0
  112. wx/lib/agw/rulerctrl.py +1885 -0
  113. wx/lib/agw/scrolledthumbnail.py +2116 -0
  114. wx/lib/agw/shapedbutton.py +1809 -0
  115. wx/lib/agw/shortcuteditor.py +2642 -0
  116. wx/lib/agw/speedmeter.py +1800 -0
  117. wx/lib/agw/supertooltip.py +1443 -0
  118. wx/lib/agw/thumbnailctrl.py +529 -0
  119. wx/lib/agw/toasterbox.py +1327 -0
  120. wx/lib/agw/ultimatelistctrl.py +13671 -0
  121. wx/lib/agw/xlsgrid.py +2111 -0
  122. wx/lib/agw/zoombar.py +1336 -0
  123. wx/lib/analogclock/__init__.py +140 -0
  124. wx/lib/analogclock/analogclock.py +630 -0
  125. wx/lib/analogclock/helpers.py +986 -0
  126. wx/lib/analogclock/lib_setup/__init__.py +0 -0
  127. wx/lib/analogclock/lib_setup/buttontreectrlpanel.py +297 -0
  128. wx/lib/analogclock/lib_setup/fontselect.py +57 -0
  129. wx/lib/analogclock/setup.py +490 -0
  130. wx/lib/analogclock/styles.py +47 -0
  131. wx/lib/anchors.py +103 -0
  132. wx/lib/art/__init__.py +4 -0
  133. wx/lib/art/flagart.py +1583 -0
  134. wx/lib/art/img2pyartprov.py +56 -0
  135. wx/lib/busy.py +152 -0
  136. wx/lib/buttons.py +1140 -0
  137. wx/lib/calendar.py +1596 -0
  138. wx/lib/checkbox.py +837 -0
  139. wx/lib/colourchooser/__init__.py +36 -0
  140. wx/lib/colourchooser/canvas.py +145 -0
  141. wx/lib/colourchooser/intl.py +24 -0
  142. wx/lib/colourchooser/pycolourbox.py +89 -0
  143. wx/lib/colourchooser/pycolourchooser.py +626 -0
  144. wx/lib/colourchooser/pycolourslider.py +98 -0
  145. wx/lib/colourchooser/pypalette.py +208 -0
  146. wx/lib/colourdb.py +740 -0
  147. wx/lib/colourselect.py +385 -0
  148. wx/lib/colourutils.py +118 -0
  149. wx/lib/combotreebox.py +944 -0
  150. wx/lib/delayedresult.py +420 -0
  151. wx/lib/dialogs.py +510 -0
  152. wx/lib/docview.py +3210 -0
  153. wx/lib/dragscroller.py +79 -0
  154. wx/lib/editor/README.txt +77 -0
  155. wx/lib/editor/__init__.py +24 -0
  156. wx/lib/editor/editor.py +974 -0
  157. wx/lib/editor/images.py +15 -0
  158. wx/lib/editor/selection.py +44 -0
  159. wx/lib/embeddedimage.py +76 -0
  160. wx/lib/eventStack.py +136 -0
  161. wx/lib/eventwatcher.py +440 -0
  162. wx/lib/evtmgr.py +521 -0
  163. wx/lib/expando.py +393 -0
  164. wx/lib/fancytext.py +494 -0
  165. wx/lib/filebrowsebutton.py +461 -0
  166. wx/lib/flashwin.py +262 -0
  167. wx/lib/flashwin_old.py +651 -0
  168. wx/lib/floatcanvas/FCEvents.py +53 -0
  169. wx/lib/floatcanvas/FCObjects.py +2910 -0
  170. wx/lib/floatcanvas/FloatCanvas.py +1025 -0
  171. wx/lib/floatcanvas/GUIMode.py +396 -0
  172. wx/lib/floatcanvas/NavCanvas.py +162 -0
  173. wx/lib/floatcanvas/Resources.py +319 -0
  174. wx/lib/floatcanvas/ScreenShot.py +1788 -0
  175. wx/lib/floatcanvas/Utilities/BBox.py +313 -0
  176. wx/lib/floatcanvas/Utilities/Colors.py +137 -0
  177. wx/lib/floatcanvas/Utilities/GUI.py +91 -0
  178. wx/lib/floatcanvas/Utilities/__init__.py +7 -0
  179. wx/lib/floatcanvas/__init__.py +124 -0
  180. wx/lib/foldmenu.py +89 -0
  181. wx/lib/gestures.py +310 -0
  182. wx/lib/gizmos/__init__.py +18 -0
  183. wx/lib/gizmos/dynamicsash.py +1202 -0
  184. wx/lib/gizmos/ledctrl.py +299 -0
  185. wx/lib/gizmos/treelistctrl.py +87 -0
  186. wx/lib/graphics.py +1942 -0
  187. wx/lib/gridmovers.py +516 -0
  188. wx/lib/iewin.py +249 -0
  189. wx/lib/iewin_old.py +894 -0
  190. wx/lib/imagebrowser.py +853 -0
  191. wx/lib/imageutils.py +163 -0
  192. wx/lib/infoframe.py +490 -0
  193. wx/lib/inspection.py +1254 -0
  194. wx/lib/intctrl.py +990 -0
  195. wx/lib/itemspicker.py +256 -0
  196. wx/lib/langlistctrl.py +480 -0
  197. wx/lib/layoutf.py +271 -0
  198. wx/lib/masked/__init__.py +27 -0
  199. wx/lib/masked/combobox.py +839 -0
  200. wx/lib/masked/ctrl.py +108 -0
  201. wx/lib/masked/ipaddrctrl.py +241 -0
  202. wx/lib/masked/maskededit.py +7262 -0
  203. wx/lib/masked/numctrl.py +2000 -0
  204. wx/lib/masked/textctrl.py +465 -0
  205. wx/lib/masked/timectrl.py +1465 -0
  206. wx/lib/mixins/__init__.py +17 -0
  207. wx/lib/mixins/grid.py +47 -0
  208. wx/lib/mixins/gridlabelrenderer.py +277 -0
  209. wx/lib/mixins/imagelist.py +77 -0
  210. wx/lib/mixins/inspection.py +184 -0
  211. wx/lib/mixins/listctrl.py +893 -0
  212. wx/lib/mixins/rubberband.py +403 -0
  213. wx/lib/mixins/treemixin.py +678 -0
  214. wx/lib/msgpanel.py +95 -0
  215. wx/lib/multisash.py +746 -0
  216. wx/lib/myole4ax.idl +178 -0
  217. wx/lib/myole4ax.tlb +0 -0
  218. wx/lib/newevent.py +229 -0
  219. wx/lib/newevent.pyi +25 -0
  220. wx/lib/nvdlg.py +156 -0
  221. wx/lib/ogl/__init__.py +13 -0
  222. wx/lib/ogl/basic.py +3989 -0
  223. wx/lib/ogl/bmpshape.py +86 -0
  224. wx/lib/ogl/canvas.py +467 -0
  225. wx/lib/ogl/composit.py +1576 -0
  226. wx/lib/ogl/diagram.py +230 -0
  227. wx/lib/ogl/divided.py +482 -0
  228. wx/lib/ogl/drawn.py +898 -0
  229. wx/lib/ogl/lines.py +1809 -0
  230. wx/lib/ogl/oglmisc.py +607 -0
  231. wx/lib/pdfviewer/__init__.py +113 -0
  232. wx/lib/pdfviewer/bitmaps/ArrowLeft.png +0 -0
  233. wx/lib/pdfviewer/bitmaps/ArrowRight.png +0 -0
  234. wx/lib/pdfviewer/bitmaps/DirectionH.png +0 -0
  235. wx/lib/pdfviewer/bitmaps/DirectionV.png +0 -0
  236. wx/lib/pdfviewer/bitmaps/PlayerFirst.png +0 -0
  237. wx/lib/pdfviewer/bitmaps/PlayerLast.png +0 -0
  238. wx/lib/pdfviewer/bitmaps/PlayerNext.png +0 -0
  239. wx/lib/pdfviewer/bitmaps/PlayerPrev.png +0 -0
  240. wx/lib/pdfviewer/bitmaps/Printer.png +0 -0
  241. wx/lib/pdfviewer/bitmaps/ReadMe.txt +28 -0
  242. wx/lib/pdfviewer/bitmaps/Save.png +0 -0
  243. wx/lib/pdfviewer/bitmaps/ZoomIn.png +0 -0
  244. wx/lib/pdfviewer/bitmaps/ZoomOut.png +0 -0
  245. wx/lib/pdfviewer/bitmaps/encode_bitmaps.py +37 -0
  246. wx/lib/pdfviewer/buttonpanel.py +285 -0
  247. wx/lib/pdfviewer/images.py +240 -0
  248. wx/lib/pdfviewer/viewer.py +1118 -0
  249. wx/lib/pdfwin.py +295 -0
  250. wx/lib/pdfwin_old.py +789 -0
  251. wx/lib/platebtn.py +789 -0
  252. wx/lib/plot/CHANGELOG.md +150 -0
  253. wx/lib/plot/README.md +16 -0
  254. wx/lib/plot/__init__.py +46 -0
  255. wx/lib/plot/__main__.py +5 -0
  256. wx/lib/plot/examples/__init__.py +0 -0
  257. wx/lib/plot/examples/demo.py +1010 -0
  258. wx/lib/plot/examples/simple_example.py +56 -0
  259. wx/lib/plot/plotcanvas.py +2985 -0
  260. wx/lib/plot/polyobjects.py +1524 -0
  261. wx/lib/plot/utils.py +334 -0
  262. wx/lib/popupctl.py +251 -0
  263. wx/lib/printout.py +1155 -0
  264. wx/lib/progressindicator.py +151 -0
  265. wx/lib/pubsub/LICENSE_BSD_Simple.txt +23 -0
  266. wx/lib/pubsub/README_WxPython.txt +22 -0
  267. wx/lib/pubsub/RELEASE_NOTES.txt +71 -0
  268. wx/lib/pubsub/__init__.py +25 -0
  269. wx/lib/pubsub/core/__init__.py +92 -0
  270. wx/lib/pubsub/core/arg1/__init__.py +16 -0
  271. wx/lib/pubsub/core/arg1/listenerimpl.py +97 -0
  272. wx/lib/pubsub/core/arg1/publisher.py +40 -0
  273. wx/lib/pubsub/core/arg1/publishermixin.py +34 -0
  274. wx/lib/pubsub/core/arg1/topicargspecimpl.py +66 -0
  275. wx/lib/pubsub/core/arg1/topicmgrimpl.py +19 -0
  276. wx/lib/pubsub/core/callables.py +198 -0
  277. wx/lib/pubsub/core/imp2.py +62 -0
  278. wx/lib/pubsub/core/itopicdefnprovider.py +0 -0
  279. wx/lib/pubsub/core/kwargs/__init__.py +16 -0
  280. wx/lib/pubsub/core/kwargs/datamsg.py +27 -0
  281. wx/lib/pubsub/core/kwargs/listenerimpl.py +93 -0
  282. wx/lib/pubsub/core/kwargs/publisher.py +77 -0
  283. wx/lib/pubsub/core/kwargs/publishermixin.py +65 -0
  284. wx/lib/pubsub/core/kwargs/topicargspecimpl.py +216 -0
  285. wx/lib/pubsub/core/kwargs/topicmgrimpl.py +13 -0
  286. wx/lib/pubsub/core/listener.py +40 -0
  287. wx/lib/pubsub/core/listenerbase.py +185 -0
  288. wx/lib/pubsub/core/notificationmgr.py +185 -0
  289. wx/lib/pubsub/core/publisherbase.py +189 -0
  290. wx/lib/pubsub/core/topicargspec.py +77 -0
  291. wx/lib/pubsub/core/topicdefnprovider.py +631 -0
  292. wx/lib/pubsub/core/topicexc.py +72 -0
  293. wx/lib/pubsub/core/topicmgr.py +454 -0
  294. wx/lib/pubsub/core/topicobj.py +472 -0
  295. wx/lib/pubsub/core/topictreetraverser.py +143 -0
  296. wx/lib/pubsub/core/topicutils.py +119 -0
  297. wx/lib/pubsub/core/treeconfig.py +21 -0
  298. wx/lib/pubsub/core/validatedefnargs.py +29 -0
  299. wx/lib/pubsub/core/weakmethod.py +102 -0
  300. wx/lib/pubsub/policies.py +24 -0
  301. wx/lib/pubsub/pub.py +199 -0
  302. wx/lib/pubsub/setuparg1.py +47 -0
  303. wx/lib/pubsub/setupkwargs.py +29 -0
  304. wx/lib/pubsub/utils/__init__.py +27 -0
  305. wx/lib/pubsub/utils/exchandling.py +100 -0
  306. wx/lib/pubsub/utils/misc.py +99 -0
  307. wx/lib/pubsub/utils/notification.py +331 -0
  308. wx/lib/pubsub/utils/topictreeprinter.py +195 -0
  309. wx/lib/pubsub/utils/xmltopicdefnprovider.py +286 -0
  310. wx/lib/pydocview.py +3300 -0
  311. wx/lib/rcsizer.py +227 -0
  312. wx/lib/resizewidget.py +357 -0
  313. wx/lib/scrolledpanel.py +243 -0
  314. wx/lib/sheet.py +350 -0
  315. wx/lib/sized_controls.py +691 -0
  316. wx/lib/softwareupdate.py +355 -0
  317. wx/lib/splitter.py +925 -0
  318. wx/lib/statbmp.py +199 -0
  319. wx/lib/stattext.py +321 -0
  320. wx/lib/throbber.py +424 -0
  321. wx/lib/ticker.py +306 -0
  322. wx/lib/ticker_xrc.py +48 -0
  323. wx/lib/utils.py +89 -0
  324. wx/lib/wordwrap.py +97 -0
  325. wx/lib/wxcairo/__init__.py +139 -0
  326. wx/lib/wxcairo/wx_cairocffi.py +200 -0
  327. wx/lib/wxcairo/wx_pycairo.py +455 -0
  328. wx/lib/wxpTag.py +274 -0
  329. wx/libcairo-2.dll +0 -0
  330. wx/locale/af/LC_MESSAGES/wxstd.mo +0 -0
  331. wx/locale/an/LC_MESSAGES/wxstd.mo +0 -0
  332. wx/locale/ar/LC_MESSAGES/wxstd.mo +0 -0
  333. wx/locale/ca/LC_MESSAGES/wxstd.mo +0 -0
  334. wx/locale/ca@valencia/LC_MESSAGES/wxstd.mo +0 -0
  335. wx/locale/co/LC_MESSAGES/wxstd.mo +0 -0
  336. wx/locale/cs/LC_MESSAGES/wxstd.mo +0 -0
  337. wx/locale/da/LC_MESSAGES/wxstd.mo +0 -0
  338. wx/locale/de/LC_MESSAGES/wxstd.mo +0 -0
  339. wx/locale/el/LC_MESSAGES/wxstd.mo +0 -0
  340. wx/locale/es/LC_MESSAGES/wxstd.mo +0 -0
  341. wx/locale/eu/LC_MESSAGES/wxstd.mo +0 -0
  342. wx/locale/fa_IR/LC_MESSAGES/wxstd.mo +0 -0
  343. wx/locale/fi/LC_MESSAGES/wxstd.mo +0 -0
  344. wx/locale/fr/LC_MESSAGES/wxstd.mo +0 -0
  345. wx/locale/gl_ES/LC_MESSAGES/wxstd.mo +0 -0
  346. wx/locale/hi/LC_MESSAGES/wxstd.mo +0 -0
  347. wx/locale/hr/LC_MESSAGES/wxstd.mo +0 -0
  348. wx/locale/hu/LC_MESSAGES/wxstd.mo +0 -0
  349. wx/locale/id/LC_MESSAGES/wxstd.mo +0 -0
  350. wx/locale/it/LC_MESSAGES/wxstd.mo +0 -0
  351. wx/locale/ja/LC_MESSAGES/wxstd.mo +0 -0
  352. wx/locale/ka/LC_MESSAGES/wxstd.mo +0 -0
  353. wx/locale/ko_KR/LC_MESSAGES/wxstd.mo +0 -0
  354. wx/locale/lt/LC_MESSAGES/wxstd.mo +0 -0
  355. wx/locale/lv/LC_MESSAGES/wxstd.mo +0 -0
  356. wx/locale/ms/LC_MESSAGES/wxstd.mo +0 -0
  357. wx/locale/nb/LC_MESSAGES/wxstd.mo +0 -0
  358. wx/locale/ne/LC_MESSAGES/wxstd.mo +0 -0
  359. wx/locale/nl/LC_MESSAGES/wxstd.mo +0 -0
  360. wx/locale/pl/LC_MESSAGES/wxstd.mo +0 -0
  361. wx/locale/pt/LC_MESSAGES/wxstd.mo +0 -0
  362. wx/locale/pt_BR/LC_MESSAGES/wxstd.mo +0 -0
  363. wx/locale/ro/LC_MESSAGES/wxstd.mo +0 -0
  364. wx/locale/ru/LC_MESSAGES/wxstd.mo +0 -0
  365. wx/locale/sk/LC_MESSAGES/wxstd.mo +0 -0
  366. wx/locale/sl/LC_MESSAGES/wxstd.mo +0 -0
  367. wx/locale/sq/LC_MESSAGES/wxstd.mo +0 -0
  368. wx/locale/sr/LC_MESSAGES/wxstd.mo +0 -0
  369. wx/locale/sv/LC_MESSAGES/wxstd.mo +0 -0
  370. wx/locale/ta/LC_MESSAGES/wxstd.mo +0 -0
  371. wx/locale/tr/LC_MESSAGES/wxstd.mo +0 -0
  372. wx/locale/uk/LC_MESSAGES/wxstd.mo +0 -0
  373. wx/locale/vi/LC_MESSAGES/wxstd.mo +0 -0
  374. wx/locale/zh_CN/LC_MESSAGES/wxstd.mo +0 -0
  375. wx/locale/zh_TW/LC_MESSAGES/wxstd.mo +0 -0
  376. wx/media.py +30 -0
  377. wx/media.pyi +272 -0
  378. wx/msw.py +16 -0
  379. wx/msw.pyi +91 -0
  380. wx/propgrid.py +498 -0
  381. wx/propgrid.pyi +7427 -0
  382. wx/py/CHANGES.txt +796 -0
  383. wx/py/Py.ico +0 -0
  384. wx/py/PyAlaCarte.py +34 -0
  385. wx/py/PyAlaMode.py +34 -0
  386. wx/py/PyAlaModeTest.py +33 -0
  387. wx/py/PyCrust.ico +0 -0
  388. wx/py/PyCrust.py +78 -0
  389. wx/py/PyCrust_16.png +0 -0
  390. wx/py/PyCrust_32.png +0 -0
  391. wx/py/PyFilling.py +35 -0
  392. wx/py/PyShell.py +78 -0
  393. wx/py/PySlices.ico +0 -0
  394. wx/py/PySlices.py +98 -0
  395. wx/py/PySlicesShell.py +94 -0
  396. wx/py/PySlices_16.png +0 -0
  397. wx/py/PySlices_32.png +0 -0
  398. wx/py/PyWrap.py +52 -0
  399. wx/py/README.txt +77 -0
  400. wx/py/__init__.py +20 -0
  401. wx/py/buffer.py +136 -0
  402. wx/py/crust.py +403 -0
  403. wx/py/crustslices.py +403 -0
  404. wx/py/dispatcher.py +259 -0
  405. wx/py/document.py +37 -0
  406. wx/py/editor.py +844 -0
  407. wx/py/editwindow.py +316 -0
  408. wx/py/filling.py +358 -0
  409. wx/py/frame.py +976 -0
  410. wx/py/images.py +212 -0
  411. wx/py/interpreter.py +161 -0
  412. wx/py/introspect.py +402 -0
  413. wx/py/magic.py +98 -0
  414. wx/py/parse.py +134 -0
  415. wx/py/path.py +36 -0
  416. wx/py/pseudo.py +99 -0
  417. wx/py/shell.py +1579 -0
  418. wx/py/sliceshell.py +3805 -0
  419. wx/py/tests/test_interpreter.py +71 -0
  420. wx/py/tests/test_introspect.py +810 -0
  421. wx/py/tests/test_pseudo.py +70 -0
  422. wx/py/tests/test_version.py +36 -0
  423. wx/py/tests/testall.py +22 -0
  424. wx/py/version.py +7 -0
  425. wx/py.typed +0 -0
  426. wx/ribbon.py +48 -0
  427. wx/ribbon.pyi +3099 -0
  428. wx/richtext.py +141 -0
  429. wx/richtext.pyi +13581 -0
  430. wx/siplib.cp315-win_amd64.pyd +0 -0
  431. wx/siplib.pyi +19 -0
  432. wx/stc.py +59 -0
  433. wx/stc.pyi +9918 -0
  434. wx/svg/__init__.py +363 -0
  435. wx/svg/_nanosvg.cp315-win_amd64.pyd +0 -0
  436. wx/tools/__init__.py +18 -0
  437. wx/tools/dbg.py +268 -0
  438. wx/tools/genaxmodule.py +50 -0
  439. wx/tools/helpviewer.py +92 -0
  440. wx/tools/img2img.py +85 -0
  441. wx/tools/img2png.py +54 -0
  442. wx/tools/img2py.py +306 -0
  443. wx/tools/img2xpm.py +54 -0
  444. wx/tools/pywxrc.py +951 -0
  445. wx/tools/wxget.py +254 -0
  446. wx/tools/wxget_docs_demo.py +183 -0
  447. wx/wxbase334u_net_vc140_x64.dll +0 -0
  448. wx/wxbase334u_vc140_x64.dll +0 -0
  449. wx/wxbase334u_xml_vc140_x64.dll +0 -0
  450. wx/wxmsw334u_adv_vc140_x64.dll +0 -0
  451. wx/wxmsw334u_aui_vc140_x64.dll +0 -0
  452. wx/wxmsw334u_core_vc140_x64.dll +0 -0
  453. wx/wxmsw334u_gl_vc140_x64.dll +0 -0
  454. wx/wxmsw334u_html_vc140_x64.dll +0 -0
  455. wx/wxmsw334u_media_vc140_x64.dll +0 -0
  456. wx/wxmsw334u_propgrid_vc140_x64.dll +0 -0
  457. wx/wxmsw334u_qa_vc140_x64.dll +0 -0
  458. wx/wxmsw334u_ribbon_vc140_x64.dll +0 -0
  459. wx/wxmsw334u_richtext_vc140_x64.dll +0 -0
  460. wx/wxmsw334u_stc_vc140_x64.dll +0 -0
  461. wx/wxmsw334u_webview_vc140_x64.dll +0 -0
  462. wx/wxmsw334u_xrc_vc140_x64.dll +0 -0
  463. wx/xml.py +18 -0
  464. wx/xml.pyi +728 -0
  465. wx/xrc.py +68 -0
  466. wx/xrc.pyi +896 -0
  467. wxpython-4.3.2.dist-info/METADATA +71 -0
  468. wxpython-4.3.2.dist-info/RECORD +472 -0
  469. wxpython-4.3.2.dist-info/WHEEL +5 -0
  470. wxpython-4.3.2.dist-info/entry_points.txt +13 -0
  471. wxpython-4.3.2.dist-info/licenses/LICENSE.txt +610 -0
  472. wxpython-4.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1118 @@
1
+ # Name: viewer.py
2
+ # Package: wx.lib.pdfviewer
3
+ #
4
+ # Purpose: A PDF report viewer class
5
+ #
6
+ # Author: David Hughes dfh@forestfield.co.uk
7
+ # Copyright: Forestfield Software Ltd
8
+ # Licence: Same as wxPython host
9
+
10
+ # History: Created 17 Jun 2009
11
+ #
12
+ # 08 Oct 2011, Michael Hipp michael@redmule.com
13
+ # Added prompt, printer_name, orientation options to
14
+ # pdfViewer.Print(). Added option to pdfViewer.LoadFile() to
15
+ # accept a file-like object as well as a path string
16
+ #
17
+ # Tags: phoenix-port, documented, unittest
18
+ #
19
+ #----------------------------------------------------------------------------
20
+
21
+ """
22
+
23
+ This module provides the :class:`~wx.lib.pdfviewer.viewer.pdfViewer` to view PDF
24
+ files.
25
+ """
26
+ import bisect
27
+ import itertools
28
+ import copy
29
+ import shutil
30
+ from io import BytesIO
31
+
32
+ import wx
33
+
34
+ VERBOSE = True
35
+
36
+ try:
37
+ # see http://pythonhosted.org/PyMuPDF - documentation & installation
38
+ try:
39
+ import pymupdf
40
+ except ImportError:
41
+ import fitz as pymupdf
42
+ mupdf = True
43
+ if VERBOSE: print('pdfviewer using PyMuPDF (GPL)')
44
+ except ImportError:
45
+ mupdf = False
46
+ try:
47
+ # see http://pythonhosted.org/PyPDF2
48
+ import PyPDF2
49
+ from PyPDF2 import PdfFileReader
50
+ from PyPDF2.pdf import ContentStream, PageObject
51
+ from PyPDF2.filters import ASCII85Decode, FlateDecode
52
+ if VERBOSE: print('pdfviewer using PyPDF2')
53
+ except ImportError:
54
+ msg = "PyMuPDF or PyPDF2 must be available to use pdfviewer"
55
+ raise ImportError(msg)
56
+
57
+ GraphicsContext = wx.GraphicsContext
58
+ have_cairo = False
59
+ if not mupdf:
60
+ try:
61
+ import wx.lib.wxcairo as wxcairo
62
+ import cairo
63
+ from wx.lib.graphics import GraphicsContext
64
+ have_cairo = True
65
+ if VERBOSE: print('pdfviewer using Cairo')
66
+ except ImportError:
67
+ if VERBOSE: print('pdfviewer using wx.GraphicsContext')
68
+
69
+ # New PageObject method added by Forestfield Software
70
+ def extractOperators(self):
71
+ """
72
+ Locate and return all commands in the order they
73
+ occur in the content stream
74
+ """
75
+ ops = []
76
+ content = self["/Contents"].getObject()
77
+ if not isinstance(content, ContentStream):
78
+ content = ContentStream(content, self.pdf)
79
+ for op in content.operations:
80
+ if type(op[1] == bytes):
81
+ op = (op[0], op[1].decode())
82
+ ops.append(op)
83
+ return ops
84
+ # Inject this method into the PageObject class
85
+ PageObject.extractOperators = extractOperators
86
+
87
+ # If reportlab is installed, use its stringWidth metric. For justifying text,
88
+ # where widths are cumulative, dc.GetTextExtent consistently underestimates,
89
+ # possibly because it returns integer rather than float.
90
+ try:
91
+ from reportlab.pdfbase.pdfmetrics import stringWidth
92
+ have_rlwidth = True
93
+ if VERBOSE: print('pdfviewer using reportlab stringWidth function')
94
+ except ImportError:
95
+ have_rlwidth = False
96
+
97
+ #----------------------------------------------------------------------------
98
+
99
+ class pdfViewer(wx.ScrolledWindow):
100
+ """
101
+ View pdf file in a scrolled window. Contents are read from PDF file
102
+ and rendered in a GraphicsContext. Show visible window contents
103
+ as quickly as possible then, when using pyPDF, read the whole file and build
104
+ the set of drawing commands for each page. This can take time for a big file or if
105
+ there are complex drawings eg. ReportLab's colour shading inside charts and a
106
+ progress bar can be displayed by setting self.ShowLoadProgress = True (default)
107
+ """
108
+ def __init__(self, parent, nid, pos, size, style):
109
+ """
110
+ Default class constructor.
111
+
112
+ :param wx.Window `parent`: parent window. Must not be ``None``;
113
+ :param integer `nid`: window identifier. A value of -1 indicates a default value;
114
+ :param `pos`: the control position. A value of (-1, -1) indicates a default position,
115
+ chosen by either the windowing system or wxPython, depending on platform;
116
+ :type `pos`: tuple or :class:`wx.Point`
117
+ :param `size`: the control size. A value of (-1, -1) indicates a default size,
118
+ chosen by either the windowing system or wxPython, depending on platform;
119
+ :type `size`: tuple or :class:`wx.Size`
120
+ :param integer `style`: the button style (unused);
121
+
122
+ """
123
+ wx.ScrolledWindow.__init__(self, parent, nid, pos, size,
124
+ style | wx.NO_FULL_REPAINT_ON_RESIZE)
125
+ self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) # recommended in wxWidgets docs
126
+ self.buttonpanel = None # reference to panel is set by their common parent
127
+ self._showLoadProgress = (not mupdf)
128
+
129
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
130
+ self.Bind(wx.EVT_SIZE, self.OnResize)
131
+ self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
132
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
133
+ self.have_file = False
134
+ self.resizing = False
135
+ self.numpages = None
136
+ self.zoomscale = -1 # fit page to screen width
137
+ self.nom_page_gap = 20 # nominal inter-page gap (points)
138
+ self.scrollrate = 20 # pixels per scrollbar increment
139
+ self.page_buffer_valid = False
140
+ self.page_after_zoom_change = None
141
+ self.ClearBackground()
142
+
143
+ def OnIdle(self, event):
144
+ """
145
+ Redraw on resize.
146
+ """
147
+ if self.resizing:
148
+ self.page_buffer_valid = False
149
+ self.Render()
150
+ self.resizing = False
151
+ event.Skip()
152
+
153
+ def OnResize(self, event):
154
+ """
155
+ Buffer size change due to client area resize.
156
+ """
157
+ self.resizing = True
158
+ event.Skip()
159
+
160
+ def OnScroll(self, event):
161
+ """
162
+ Recalculate and redraw visible area. CallAfter is *essential*
163
+ for coordination.
164
+ """
165
+ wx.CallAfter(self.Render)
166
+ event.Skip()
167
+
168
+ def OnPaint(self, event):
169
+ """
170
+ Refresh visible window with bitmap contents.
171
+ """
172
+ paintDC = wx.PaintDC(self)
173
+ paintDC.Clear() # in case buffer now smaller than visible window
174
+ if hasattr(self, 'pdc'):
175
+ paintDC.Blit(0, 0, self.winwidth, self.winheight, self.pdc,
176
+ self.xshift, self.yshift)
177
+
178
+ #----------------------------------------------------------------------------
179
+
180
+ # This section defines the externally callable methods:
181
+ # LoadFile, Save, Print, SetZoom, and GoPage
182
+ # also the getter and setter for ShowLoadProgress
183
+ # that is only applicable if using PyPDF2
184
+
185
+ def LoadFile(self, pdf_file):
186
+ """
187
+ Read pdf file. Assume all pages are same size, for now.
188
+
189
+ :param `pdf_file`: can be either a string holding
190
+ a filename path or a file-like object.
191
+ """
192
+ def create_fileobject(filename):
193
+ """
194
+ Create and return a file object with the contents of filename,
195
+ only used for testing.
196
+ """
197
+ with open(filename, 'rb') as f:
198
+ stream = f.read()
199
+ return BytesIO(stream)
200
+
201
+ self.pdfpathname = ''
202
+ if isinstance(pdf_file, str):
203
+ # a filename/path string, save its name
204
+ self.pdfpathname = pdf_file
205
+ # remove comment from next line to test using a file-like object
206
+ # pdf_file = create_fileobject(pdf_file)
207
+ if mupdf:
208
+ self.pdfdoc = mupdfProcessor(self, pdf_file)
209
+ else:
210
+ self.pdfdoc = pypdfProcessor(self, pdf_file, self.ShowLoadProgress)
211
+
212
+ self.numpages = self.pdfdoc.numpages
213
+ self.pagesizes = [self.pdfdoc.GetPageSize(i) for i in range(self.numpages)]
214
+
215
+ self.page_buffer_valid = False
216
+ self.Scroll(0, 0) # in case this is a re-LoadFile
217
+ self.CalculateDimensions() # to get initial visible page range
218
+ # draw and display the minimal set of pages
219
+ self.pdfdoc.DrawFile(self.frompage, self.topage)
220
+ self.have_file = True
221
+ # now draw full set of pages
222
+ wx.CallAfter(self.pdfdoc.DrawFile, 0, self.numpages-1)
223
+
224
+ def Save(self):
225
+ "Save a copy of the pdf file if it was originally named"
226
+ if self.pdfpathname:
227
+ wild = "Portable document format (*.pdf)|*.pdf"
228
+ dlg = wx.FileDialog(self, message="Save file as ...",
229
+ wildcard=wild, style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
230
+ if dlg.ShowModal() == wx.ID_OK:
231
+ pathname = dlg.GetPath()
232
+ shutil.copy(self.pdfpathname, pathname)
233
+ dlg.Destroy()
234
+
235
+ def Print(self, prompt=True, printer_name=None, orientation=None):
236
+ """
237
+ Print the pdf.
238
+
239
+ :param boolean `prompt`: show the print dialog to the user (True/False). If
240
+ False, the print dialog will not be shown and the pdf will be printed
241
+ immediately. Default: True.
242
+ :param string `printer_name`: the name of the printer that is to
243
+ receive the printout. Default: as set by the O/S.
244
+ :param `orientation`: select the orientation (:class:`wx.PORTRAIT` or
245
+ :class:`wx.LANDSCAPE`) for the printout. Default: as set by the O/S.
246
+ """
247
+ pdd = wx.PrintDialogData()
248
+ pdd.SetMinPage(1)
249
+ pdd.SetFromPage(1)
250
+ pdd.SetMaxPage(self.numpages)
251
+ pdd.SetToPage(self.numpages)
252
+ pdata = pdd.GetPrintData()
253
+ if printer_name:
254
+ pdata.SetPrinterName(printer_name)
255
+ if orientation:
256
+ pdata.SetOrientation(orientation)
257
+ # PrintData does not return actual PrintQuality - it can't as printer_name not known
258
+ # but it defaults to wx.PRINT_QUALITY_HIGH, overriding user's own setting for the
259
+ # printer. However calling SetQuality with a value of 0 seems to leave the printer
260
+ # setting untouched
261
+ pdata.SetQuality(0)
262
+ printer = wx.Printer(pdd)
263
+ printout = pdfPrintout('', self)
264
+ if (not printer.Print(self, printout, prompt=prompt) and
265
+ printer.GetLastError() == wx.PRINTER_ERROR):
266
+ dlg = wx.MessageDialog(self, 'Unable to perform printing',
267
+ 'Printer' , wx.OK | wx.ICON_INFORMATION)
268
+ dlg.ShowModal()
269
+ dlg.Destroy()
270
+ printout.Destroy()
271
+
272
+ def SetZoom(self, zoomscale):
273
+ """
274
+ Positive integer or floating zoom scale will render the file at corresponding
275
+ size where 1.0 is "actual" point size (1/72").
276
+ -1 fits page width and -2 fits page height into client area
277
+ Redisplay the current page(s) at the new size
278
+
279
+ :param `zoomscale`: an integer or float
280
+
281
+ """
282
+ pagenow = self.frompage
283
+ self.zoomscale = zoomscale
284
+ self.page_buffer_valid = False
285
+ # calling GoPage now will trigger rendering at the new size but the page location
286
+ # will be calculated based on the old zoom scale - so save the required page number
287
+ # and call GoPage again *after* rendering at the new size
288
+ self.page_after_zoom_change = pagenow
289
+ self.GoPage(pagenow)
290
+
291
+ def GoPage(self, pagenum):
292
+ """
293
+ Go to page
294
+
295
+ :param integer `pagenum`: go to the provided page number if it is valid
296
+
297
+ """
298
+ # calling Scroll sometimes doesn't raise wx.EVT_SCROLLWIN eg Windows 8 64 bit - so
299
+ wx.CallAfter(self.Render)
300
+
301
+ if not hasattr(self, "cumYpagespixels"):
302
+ return False # This could happen if the file is still loading
303
+
304
+ if pagenum > 0 and pagenum <= self.numpages:
305
+ self.Scroll(0, self.cumYpagespixels[pagenum-1] //
306
+ self.GetScrollPixelsPerUnit()[1])
307
+ return True
308
+ else:
309
+ self.Scroll(0, 0)
310
+ return False
311
+
312
+ @property
313
+ def ShowLoadProgress(self):
314
+ """Property to control if file reading progress is shown (PyPDF2 only)"""
315
+ return self._showLoadProgress
316
+
317
+ @ShowLoadProgress.setter
318
+ def ShowLoadProgress(self, flag):
319
+ """Setter for showLoadProgress."""
320
+ self._showLoadProgress = flag
321
+
322
+ #----------------------------------------------------------------------------
323
+
324
+ # This section is concerned with rendering a sub-set of drawing commands on demand
325
+
326
+ def CalculateDimensions(self):
327
+ """
328
+ Compute the required buffer sizes to hold the viewed rectangle and
329
+ the range of pages visible. Set self.page_buffer_valid = False if
330
+ the current set of rendered pages changes
331
+ """
332
+ self.frompage = 0
333
+ self.topage = 0
334
+ device_scale = wx.ClientDC(self).GetPPI()[0]/72.0 # pixels per inch/points per inch
335
+ self.font_scale_metrics = 1.0
336
+ self.font_scale_size = 1.0
337
+ # for Windows only with wx.GraphicsContext the rendered font size is too big
338
+ # in the ratio of screen pixels per inch to points per inch
339
+ # and font metrics are too big in the same ratio for both for Cairo and wx.GC
340
+ if wx.PlatformInfo[1] == 'wxMSW':
341
+ self.font_scale_metrics = 1.0 / device_scale
342
+ if not have_cairo:
343
+ self.font_scale_size = 1.0 / device_scale
344
+
345
+ clientSize = self.GetClientSize()
346
+ if clientSize.width < 5 or clientSize.height < 5:
347
+ return False # Window is too small to render
348
+ self.winwidth, self.winheight = clientSize
349
+ self.Ypages = [self.pagesizes[pageno][1] + self.nom_page_gap
350
+ for pageno in range(self.numpages)]
351
+ if self.zoomscale > 0.0:
352
+ self.scales = [self.zoomscale * device_scale]*self.numpages
353
+ else:
354
+ if int(self.zoomscale) == -1: # fit width
355
+ self.scales = [self.winwidth / self.pagesizes[pageno][0]
356
+ for pageno in range(self.numpages)]
357
+ else: # fit page
358
+ self.scales = [self.winheight / self.pagesizes[pageno][1]
359
+ for pageno in range(self.numpages)]
360
+ self.Xpagespixels = [int(round(self.pagesizes[pageno][0] * self.scales[pageno]))
361
+ for pageno in range(self.numpages)]
362
+
363
+ self.Ypagespixels = [None]*self.numpages
364
+ self.page_gaps = [None]*self.numpages
365
+ for pageno in range(self.numpages):
366
+ Ypagepixels = int(round(self.Ypages[pageno] * self.scales[pageno]))
367
+ # adjust Ypagespixels (total number of vertical pixels per page including bottom
368
+ # inter-page gap so Ypagepixels is a whole number of scroll increments and pages
369
+ # change precisely on a scroll click
370
+ idiv = Ypagepixels // self.scrollrate
371
+ nlo = idiv * self.scrollrate
372
+ nhi = (idiv + 1) * self.scrollrate
373
+ if nhi - Ypagepixels < Ypagepixels - nlo:
374
+ self.Ypagespixels[pageno] = nhi
375
+ else:
376
+ self.Ypagespixels[pageno] = nlo
377
+ self.page_gaps[pageno] = (self.Ypagespixels[pageno]/self.scales[pageno] -
378
+ self.pagesizes[pageno][1])
379
+
380
+ self.cumYpagespixels = list(itertools.accumulate(self.Ypagespixels))
381
+
382
+ self.maxwidth = max(self.winwidth,
383
+ max(self.Xpagespixels[pageno] for pageno in range(self.numpages)))
384
+ self.maxheight = max(self.winheight, self.cumYpagespixels[-1])
385
+ self.SetVirtualSize((self.maxwidth, self.maxheight))
386
+ self.SetScrollRate(self.scrollrate, self.scrollrate)
387
+
388
+ xv, yv = self.GetViewStart()
389
+ dx, dy = self.GetScrollPixelsPerUnit()
390
+
391
+ self.x0, self.y0 = (xv * dx, yv * dy)
392
+ self.frompage = max(bisect.bisect_left(self.cumYpagespixels, self.y0+1), 0)
393
+ self.topage = min(bisect.bisect_right(self.cumYpagespixels, self.y0+self.winheight-1),
394
+ self.numpages-1)
395
+ if self.frompage > self.topage:
396
+ return False # Nothing to render. Can happen during initialization
397
+
398
+ self.page_x0 = 0
399
+ self.pagebufferwidth = max(self.Xpagespixels[pageno]
400
+ for pageno in range(self.frompage, self.topage+1))
401
+ self.page_y0 = self.cumYpagespixels[self.frompage-1] if self.frompage else 0
402
+ self.pagebufferheight = self.cumYpagespixels[self.topage] - self.page_y0
403
+
404
+ # Inform buttonpanel controls of any changes
405
+ if self.buttonpanel:
406
+ self.buttonpanel.Update(self.frompage, self.numpages,
407
+ self.scales[self.frompage]/device_scale)
408
+
409
+ self.xshift = self.x0 - self.page_x0
410
+ self.yshift = self.y0 - self.page_y0
411
+
412
+ if not self.page_buffer_valid: # via external setting
413
+ self.cur_frompage = self.frompage
414
+ self.cur_topage = self.topage
415
+ else: # page range unchanged? whole visible area will always be inside page buffer
416
+ if self.frompage != self.cur_frompage or self.topage != self.cur_topage:
417
+ self.page_buffer_valid = False # due to page buffer change
418
+ self.cur_frompage = self.frompage
419
+ self.cur_topage = self.topage
420
+
421
+ return True
422
+
423
+ def Render(self):
424
+ """
425
+ Recalculate dimensions as client area may have been scrolled or resized.
426
+ The smallest unit of rendering that can be done is the pdf page. So render
427
+ the drawing commands for the pages in the visible rectangle into a buffer
428
+ big enough to hold this set of pages. Force re-creating the page buffer
429
+ only when client view moves outside it.
430
+ With PyPDF2, use gc.Translate to render each page wrt the pdf origin,
431
+ which is at the bottom left corner of the page.
432
+ """
433
+ if not self.have_file:
434
+ return
435
+ if not self.CalculateDimensions():
436
+ return # Invalid dimensions: Nothing to render
437
+ if not self.page_buffer_valid:
438
+ # Initialize the buffer bitmap.
439
+ self.pagebuffer = wx.Bitmap(self.pagebufferwidth, self.pagebufferheight)
440
+ self.pdc = wx.MemoryDC(self.pagebuffer) # must persist
441
+
442
+ gc = GraphicsContext.Create(self.pdc) # Cairo/wx.GraphicsContext API
443
+
444
+ # white background
445
+ path = gc.CreatePath()
446
+ path.AddRectangle(0, 0,
447
+ self.pagebuffer.GetWidth(), self.pagebuffer.GetHeight())
448
+ gc.SetBrush(wx.WHITE_BRUSH)
449
+ gc.FillPath(path)
450
+
451
+ for pageno in range(self.frompage, self.topage+1):
452
+ scale = self.scales[pageno]
453
+ pagegap = self.page_gaps[pageno]
454
+ self.xpageoffset = 0 - self.x0
455
+ self.ypageoffset = (self.cumYpagespixels[pageno] - self.Ypagespixels[pageno] -
456
+ self.page_y0)
457
+
458
+ gc.PushState()
459
+ if mupdf:
460
+ gc.Translate(self.xpageoffset, self.ypageoffset)
461
+ # scaling is done inside RenderPage
462
+ else:
463
+
464
+ gc.Translate(self.xpageoffset, self.ypageoffset +
465
+ self.pagesizes[pageno][1]*scale)
466
+ gc.Scale(scale, scale)
467
+ self.pdfdoc.RenderPage(gc, pageno, scale=scale)
468
+
469
+ # Show non-page areas as gray
470
+ gc.PushState()
471
+ gc.SetBrush(wx.Brush(self.GetBackgroundColour()))
472
+ gc.SetPen(wx.TRANSPARENT_PEN)
473
+ gc.Scale(1.0, 1.0)
474
+
475
+ #inter-page gap
476
+ gc.DrawRectangle(0, self.pagesizes[pageno][1]*scale,
477
+ self.pagesizes[pageno][0]*scale, pagegap*scale)
478
+ # gap to the right of the page
479
+ extrawidth = self.winwidth - self.Xpagespixels[pageno]
480
+ if extrawidth > 0:
481
+ gc.DrawRectangle(self.pagesizes[pageno][0]*scale, 0,
482
+ extrawidth, self.Ypagespixels[pageno])
483
+ gc.PopState() # Pop non-page area
484
+
485
+ gc.PopState() # Pop page area
486
+
487
+ self.page_buffer_valid = True
488
+ self.Refresh(0) # Blit appropriate area of new or existing page buffer to screen
489
+
490
+ # ensure we stay on the same page after zoom scale is changed
491
+ if self.page_after_zoom_change:
492
+ self.GoPage(self.page_after_zoom_change)
493
+ self.page_after_zoom_change = None
494
+
495
+ #============================================================================
496
+
497
+ class mupdfProcessor(object):
498
+ """
499
+ Create an instance of this class to open a PDF file, process the contents of
500
+ each page and render each one on demand using the GPL mupdf library, which is
501
+ accessed via the pymupdf package bindings (version 1.9.1 or later)
502
+ """
503
+ def __init__(self, parent, pdf_file):
504
+ """
505
+ :param `pdf_file`: a File object or an object that supports the standard
506
+ read and seek methods similar to a File object.
507
+ Could also be a string representing a path to a PDF file.
508
+ """
509
+ self.parent = parent
510
+ if isinstance(pdf_file, str):
511
+ # a filename/path string, pass the name to pymupdf.open
512
+ pathname = pdf_file
513
+ self.pdfdoc = pymupdf.open(pathname)
514
+ else:
515
+ # assume it is a file-like object, pass the stream content to pymupdf.open
516
+ # and a '.pdf' extension in pathname to identify the stream type
517
+ pathname = 'fileobject.pdf'
518
+ if pdf_file.tell() > 0: # not positioned at start
519
+ pdf_file.seek(0)
520
+ stream = bytearray(pdf_file.read())
521
+ self.pdfdoc = pymupdf.open(pathname, stream)
522
+
523
+ try:
524
+ self.numpages = self.pdfdoc.page_count
525
+ except AttributeError: # old PyMuPDF version
526
+ self.numpages = self.pdfdoc.pageCount
527
+
528
+ self.zoom_error = False #set if memory errors during render
529
+
530
+ def GetPageSize(self, pageNum):
531
+ """ Return width, height for the page """
532
+ try:
533
+ page = self.pdfdoc.load_page(pageNum)
534
+ except AttributeError: # old PyMuPDF version
535
+ page = self.pdfdoc.loadPage(pageNum)
536
+ bound = page.bound()
537
+ return bound.width, bound.height
538
+
539
+ def DrawFile(self, frompage, topage):
540
+ """
541
+ This is a no-op for mupdf. Each page is scaled and drawn on
542
+ demand during RenderPage directly via a call to page.getPixmap()
543
+ """
544
+ self.parent.GoPage(frompage)
545
+
546
+ def RenderPage(self, gc, pageno, scale=1.0):
547
+ " Render the set of pagedrawings into gc for specified page "
548
+ try:
549
+ page = self.pdfdoc.load_page(pageno)
550
+ except AttributeError: # old PyMuPDF version
551
+ page = self.pdfdoc.loadPage(pageno)
552
+ matrix = pymupdf.Matrix(scale, scale)
553
+ try:
554
+ try:
555
+ # MUST be keyword arg(s)
556
+ pix = page.get_pixmap(matrix=matrix, alpha=False)
557
+ except AttributeError: # old PyMuPDF version
558
+ pix = page.getPixmap(matrix=matrix, alpha=False)
559
+ bmp = wx.Bitmap.FromBuffer(pix.width, pix.height, pix.samples)
560
+ gc.DrawBitmap(bmp, 0, 0, pix.width, pix.height)
561
+ self.zoom_error = False
562
+ except (RuntimeError, MemoryError):
563
+ if not self.zoom_error: # report once only
564
+ self.zoom_error = True
565
+ dlg = wx.MessageDialog(self.parent, 'Out of memory. Zoom level too high?',
566
+ 'pdf viewer' , wx.OK |wx.ICON_EXCLAMATION)
567
+ dlg.ShowModal()
568
+ dlg.Destroy()
569
+
570
+ #============================================================================
571
+
572
+ class pypdfProcessor(object):
573
+ """
574
+ Create an instance of this class to open a PDF file, process the contents of
575
+ every page using PyPDF2 then render each one on demand
576
+ """
577
+ def __init__(self, parent, fileobj, showloadprogress):
578
+ self.parent = parent
579
+ self.showloadprogress = showloadprogress
580
+ self.pdfdoc = PdfFileReader(fileobj)
581
+ self.numpages = self.pdfdoc.getNumPages()
582
+ self.pagedrawings = {}
583
+ self.unimplemented = {}
584
+ self.formdrawings = {}
585
+ self.page = None
586
+ self.gstate = None
587
+ self.saved_state = None
588
+ self.knownfont = False
589
+ self.progbar = None
590
+
591
+ def GetPageSize(self, pageNum):
592
+ mediaBox = self.pdfdoc.getPage(pageNum).mediaBox
593
+ return float(mediaBox.getUpperRight_x()), float(mediaBox.getUpperRight_y())
594
+
595
+ # These methods interpret the PDF contents as a set of drawing commands
596
+
597
+ def Progress(self, ptype, value):
598
+ " This function is called at regular intervals during Drawfile"
599
+ if ptype == 'start':
600
+ pmsg = 'Reading pdf file'
601
+ self.progbar = wx.ProgressDialog('Load file', pmsg, value, None,
602
+ wx.PD_AUTO_HIDE|
603
+ wx.PD_ESTIMATED_TIME|wx.PD_REMAINING_TIME)
604
+ elif ptype == 'progress':
605
+ self.progbar.Update(value)
606
+ elif ptype == 'end':
607
+ self.progbar.Destroy()
608
+
609
+ def DrawFile(self, frompage, topage):
610
+ """
611
+ Build set of drawing commands from PDF contents. Ideally these could be drawn
612
+ straight into a PseudoDC and the visible section painted directly into
613
+ scrolled window, but we need to be able to zoom and scale the output quickly
614
+ without having to rebuild the drawing commands (slow). So build our
615
+ own command lists, one per page, into self.pagedrawings.
616
+ """
617
+ numpages_generated = 0
618
+ rp = (self.showloadprogress and frompage == 0 and topage == self.numpages-1)
619
+ if rp: self.Progress('start', self.numpages)
620
+ for pageno in range(frompage, topage+1):
621
+ self.gstate = pdfState() # state is reset with every new page
622
+ self.saved_state = []
623
+ self.page = self.pdfdoc.getPage(pageno)
624
+ numpages_generated += 1
625
+ pdf_fonts = self.FetchFonts(self.page)
626
+ self.pagedrawings[pageno] = self.ProcessOperators(
627
+ self.page.extractOperators(), pdf_fonts)
628
+ if rp: self.Progress('progress', numpages_generated)
629
+
630
+ if rp: self.Progress('end', None)
631
+ self.parent.GoPage(frompage)
632
+
633
+ def RenderPage(self, gc, pageno, scale=None):
634
+ """
635
+ Render the set of pagedrawings
636
+ In a pdf file, bitmaps are treated as being of unit width and height and
637
+ are scaled via a previous ConcatTransform containing the corresponding width
638
+ and height as scale factors. wx.GraphicsContext/Cairo appear not to respond to
639
+ this so scaling is removed from transform and width & height are added
640
+ to the Drawbitmap call.
641
+ """
642
+ drawdict = {'ConcatTransform': gc.ConcatTransform,
643
+ 'PushState': gc.PushState,
644
+ 'PopState': gc.PopState,
645
+ 'SetFont': gc.SetFont,
646
+ 'SetPen': gc.SetPen,
647
+ 'SetBrush': gc.SetBrush,
648
+ 'DrawText': gc.DrawText,
649
+ 'DrawBitmap': gc.DrawBitmap,
650
+ 'CreatePath': gc.CreatePath,
651
+ 'DrawPath': gc.DrawPath }
652
+ for drawcmd, args, kwargs in self.pagedrawings[pageno]:
653
+ # scale font if requested by printer DC
654
+ if drawcmd == 'SetFont' and hasattr(gc, 'font_scale'):
655
+ args[0].Scale(gc.font_scale)
656
+ if drawcmd == 'ConcatTransform':
657
+ cm = gc.CreateMatrix(*args, **kwargs)
658
+ args = (cm,)
659
+ if drawcmd == 'CreatePath':
660
+ gp = drawdict[drawcmd](*args, **kwargs)
661
+ continue
662
+ elif drawcmd == 'DrawPath':
663
+ args = (gp, args[1])
664
+ if drawcmd in drawdict:
665
+ drawdict[drawcmd](*args, **kwargs)
666
+ # reset font scaling in case RenderPage call is repeated
667
+ if drawcmd == 'SetFont' and hasattr(gc, 'font_scale'):
668
+ args[0].Scale(1.0/gc.font_scale)
669
+ else:
670
+ pathdict = {'MoveToPoint': gp.MoveToPoint,
671
+ 'AddLineToPoint': gp.AddLineToPoint,
672
+ 'AddCurveToPoint': gp.AddCurveToPoint,
673
+ 'AddRectangle': gp.AddRectangle,
674
+ 'CloseSubpath': gp.CloseSubpath }
675
+ if drawcmd in pathdict:
676
+ pathdict[drawcmd](*args, **kwargs)
677
+
678
+ def FetchFonts(self, currentobject):
679
+ " Return the standard fonts in current page or form"
680
+ pdf_fonts = {}
681
+ try:
682
+ fonts = currentobject["/Resources"].getObject()['/Font']
683
+ for key in fonts:
684
+ pdf_fonts[key] = fonts[key]['/BaseFont'][1:] # remove the leading '/'
685
+ except KeyError:
686
+ pass
687
+ return pdf_fonts
688
+
689
+ def ProcessOperators(self, opslist, pdf_fonts):
690
+ """
691
+ Interpret each operation in opslist and return in drawlist.
692
+ """
693
+ drawlist = []
694
+ path = []
695
+ for operand, operator in opslist :
696
+ g = self.gstate
697
+ if operator == 'cm' and operand: # new transformation matrix
698
+ # some operands need inverting because directions of y axis
699
+ # in pdf and graphics context are opposite
700
+ a, b, c, d, e, f = [float(n) for n in operand]
701
+ drawlist.append(['ConcatTransform', (a, -b, -c, d, e, -f), {}])
702
+ elif operator == 'q': # save state
703
+ self.saved_state.append(copy.deepcopy(g))
704
+ drawlist.append(['PushState', (), {}])
705
+ elif operator == 'Q': # restore state
706
+ self.gstate = self.saved_state.pop()
707
+ drawlist.append(['PopState', (), {}])
708
+ elif operator == 'RG': # Stroke RGB
709
+ rs, gs, bs = [int(float(n)*255) for n in operand]
710
+ g.strokeRGB = wx.Colour(rs, gs, bs)
711
+ elif operator == 'rg': # Fill RGB
712
+ rf, gf, bf = [int(float(n)*255) for n in operand]
713
+ g.fillRGB = wx.Colour(rf, gf, bf)
714
+ elif operator == 'K': # Stroke CMYK
715
+ rs, gs, bs = self.ConvertCMYK(operand)
716
+ g.strokeRGB = wx.Colour(rs, gs, bs)
717
+ elif operator == 'k': # Fill CMYK
718
+ rf, gf, bf = self.ConvertCMYK(operand)
719
+ g.fillRGB = wx.Colour(rf, gf, bf)
720
+ elif operator == 'w': # Line width
721
+ g.lineWidth = max(float(operand[0]), 1.0)
722
+ elif operator == 'J': # Line cap
723
+ ix = float(operand[0])
724
+ g.lineCapStyle = {0: wx.CAP_BUTT, 1: wx.CAP_ROUND,
725
+ 2: wx.CAP_PROJECTING}[ix]
726
+ elif operator == 'j': # Line join
727
+ ix = float(operand[0])
728
+ g.lineJoinStyle = {0: wx.JOIN_MITER, 1: wx.JOIN_ROUND,
729
+ 2: wx.JOIN_BEVEL}[ix]
730
+ elif operator == 'd': # Line dash pattern
731
+ g.lineDashArray = [int(n) for n in operand[0]]
732
+ g.lineDashPhase = int(operand[1])
733
+ elif operator in ('m', 'c', 'l', 're', 'v', 'y', 'h'): # path defining ops
734
+ path.append([[float(n) for n in operand], operator])
735
+ elif operator in ('b', 'B', 'b*', 'B*', 'f', 'F', 'f*',
736
+ 's', 'S', 'n'): # path drawing ops
737
+ drawlist.extend(self.DrawPath(path, operator))
738
+ path = []
739
+ elif operator == 'BT': # begin text object
740
+ g.textMatrix = [1, 0, 0, 1, 0, 0]
741
+ g.textLineMatrix = [1, 0, 0, 1, 0, 0]
742
+ elif operator == 'ET': # end text object
743
+ continue
744
+ elif operator == 'Tm': # text matrix
745
+ g.textMatrix = [float(n) for n in operand]
746
+ g.textLineMatrix = [float(n) for n in operand]
747
+ elif operator == 'TL': # text leading
748
+ g.leading = float(operand[0])
749
+ #elif operator == 'Tc': # character spacing
750
+ # g.charSpacing = float(operand[0])
751
+ elif operator == 'Tw': # word spacing
752
+ g.wordSpacing = float(operand[0])
753
+ elif operator == 'Ts': # super/subscript
754
+ g.textRise = float(operand[0])
755
+ elif operator == 'Td': # next line via offsets
756
+ g.textLineMatrix[4] += float(operand[0])
757
+ g.textLineMatrix[5] += float(operand[1])
758
+ g.textMatrix = copy.copy(g.textLineMatrix)
759
+ elif operator == 'T*': # next line via leading
760
+ g.textLineMatrix[4] += 0
761
+ g.textLineMatrix[5] -= g.leading if g.leading is not None else 0
762
+ g.textMatrix = copy.copy(g.textLineMatrix)
763
+ elif operator == 'Tf': # text font
764
+ g.font = pdf_fonts[operand[0]]
765
+ g.fontSize = float(operand[1])
766
+ elif operator == 'Tj': # show text
767
+ drawlist.extend(self.DrawTextString(
768
+ operand[0].original_bytes.decode('latin-1')))
769
+ elif operator == 'Do': # invoke named XObject
770
+ dlist = self.InsertXObject(operand[0])
771
+ if dlist: # may be unimplemented decode
772
+ drawlist.extend(dlist)
773
+ elif operator == 'INLINE IMAGE': # special pyPdf case + operand is a dict
774
+ dlist = self.InlineImage(operand)
775
+ if dlist: # may be unimplemented decode
776
+ drawlist.extend(dlist)
777
+ else: # report once
778
+ if operator not in self.unimplemented:
779
+ if VERBOSE: print('PDF operator %s is not implemented' % operator)
780
+ self.unimplemented[operator] = 1
781
+
782
+ # Fix bitmap transform. Move the scaling from any transform matrix that precedes
783
+ # a DrawBitmap operation into the op itself - the width and height extracted from
784
+ # the bitmap is the size of the original PDF image not the size it is to be drawn
785
+ for k in range(len(drawlist)-1):
786
+ if drawlist[k][0] == 'ConcatTransform' and drawlist[k+1][0] == 'DrawBitmap':
787
+ ctargs = list(drawlist[k][1])
788
+ bmargs = list(drawlist[k+1][1])
789
+ bmargs[2] = -ctargs[3] # y position
790
+ bmargs[3] = ctargs[0] # width
791
+ bmargs[4] = ctargs[3] # height
792
+ ctargs[0] = 1.0
793
+ ctargs[3] = 1.0
794
+ drawlist[k][1] = tuple(ctargs)
795
+ drawlist[k+1][1] = tuple(bmargs)
796
+ return drawlist
797
+
798
+ def SetFont(self, pdfont, size):
799
+ """
800
+ Returns :class:`wx.Font` instance from supplied pdf font information.
801
+ """
802
+ self.knownfont = True
803
+ pdfont = pdfont.lower()
804
+ if pdfont.count('courier'):
805
+ family = wx.FONTFAMILY_MODERN
806
+ font = 'Courier New'
807
+ elif pdfont.count('helvetica'):
808
+ family = wx.FONTFAMILY_SWISS
809
+ font = 'Arial'
810
+ elif pdfont.count('times'):
811
+ family = wx.FONTFAMILY_ROMAN
812
+ font = 'Times New Roman'
813
+ elif pdfont.count('symbol'):
814
+ family = wx.FONTFAMILY_DEFAULT
815
+ font = 'Symbol'
816
+ elif pdfont.count('zapfdingbats'):
817
+ family = wx.FONTFAMILY_DEFAULT
818
+ font = 'Wingdings'
819
+ else:
820
+ if VERBOSE: print('Unknown font %s' % pdfont)
821
+ self.knownfont = False
822
+ family = wx.FONTFAMILY_SWISS
823
+ font = 'Arial'
824
+
825
+ weight = wx.FONTWEIGHT_NORMAL
826
+ if pdfont.count('bold'):
827
+ weight = wx.FONTWEIGHT_BOLD
828
+ style = wx.FONTSTYLE_NORMAL
829
+ if pdfont.count('oblique') or pdfont.count('italic'):
830
+ style = wx.FONTSTYLE_ITALIC
831
+ return wx.Font(max(1, size), family, style, weight, faceName=font)
832
+
833
+ def DrawTextString(self, text):
834
+ """
835
+ Draw a text string. Word spacing only works for horizontal text.
836
+
837
+ :param string `text`: the text to draw
838
+
839
+ """
840
+ dlist = []
841
+ g = self.gstate
842
+ f0 = self.SetFont(g.font, g.fontSize)
843
+ f0.Scale(self.parent.font_scale_metrics)
844
+ f1 = self.SetFont(g.font, g.fontSize)
845
+ f1.Scale(self.parent.font_scale_size)
846
+ dlist.append(['SetFont', (f1, g.fillRGB), {}])
847
+ if g.wordSpacing > 0:
848
+ textlist = text.split(' ')
849
+ else:
850
+ textlist = [text,]
851
+ for item in textlist:
852
+ dlist.append(self.DrawTextItem(item, f0))
853
+ return dlist
854
+
855
+ def DrawTextItem(self, textitem, f):
856
+ """
857
+ Draw a text item.
858
+
859
+ :param `textitem`: the item to draw
860
+ :param `f`: the font to use for text extent measuring
861
+
862
+ """
863
+ dc = wx.ClientDC(self.parent) # dummy dc for text extents
864
+ g = self.gstate
865
+ x = g.textMatrix[4]
866
+ y = g.textMatrix[5] + g.textRise
867
+ if g.wordSpacing > 0:
868
+ textitem += ' '
869
+ wid, ht, descend, x_lead = dc.GetFullTextExtent(textitem, f)
870
+ if have_rlwidth and self.knownfont: # use ReportLab stringWidth if available
871
+ width = stringWidth(textitem, g.font, g.fontSize)
872
+ else:
873
+ width = wid
874
+ g.textMatrix[4] += (width + g.wordSpacing) # update current x position
875
+ return ['DrawText', (textitem, x, -y-(ht-descend)), {}]
876
+
877
+ def DrawPath(self, path, action):
878
+ """
879
+ Stroke and/or fill the defined path depending on operator.
880
+ """
881
+ dlist = []
882
+ g = self.gstate
883
+ acts = {'S': (1, 0, 0),
884
+ 's': (1, 0, 0),
885
+ 'f': (0, 1, wx.WINDING_RULE),
886
+ 'F': (0, 1, wx.WINDING_RULE),
887
+ 'f*': (0, 1, wx.ODDEVEN_RULE),
888
+ 'B': (1, 1, wx.WINDING_RULE),
889
+ 'B*': (1, 1, wx.ODDEVEN_RULE),
890
+ 'b': (1, 1, wx.WINDING_RULE),
891
+ 'b*': (1, 1, wx.ODDEVEN_RULE),
892
+ 'n': (0, 0, 0) }
893
+ stroke, fill, rule = acts[action]
894
+ if action in ('s', 'b', 'b*'):
895
+ path.append([[], 'h']) # close path
896
+
897
+ if stroke:
898
+ if g.lineDashArray:
899
+ style = wx.PENSTYLE_USER_DASH
900
+ else:
901
+ style = wx.PENSTYLE_SOLID
902
+ cpen = wx.Pen(g.strokeRGB, g.lineWidth, style)
903
+ cpen.SetCap(g.lineCapStyle)
904
+ cpen.SetJoin(g.lineJoinStyle)
905
+ if g.lineDashArray:
906
+ cpen.SetDashes(g.lineDashArray)
907
+ dlist.append(['SetPen', (cpen,), {}])
908
+ else:
909
+ dlist.append(['SetPen', (wx.TRANSPARENT_PEN,), {}])
910
+
911
+ if fill:
912
+ dlist.append(['SetBrush', (wx.Brush(g.fillRGB),), {}])
913
+ else:
914
+ dlist.append(['SetBrush', (wx.TRANSPARENT_BRUSH,), {}])
915
+
916
+ dlist.append(['CreatePath', (), {}])
917
+ for xylist, op in path:
918
+ if op == 'm': # move (to) current point
919
+ x0 = xc = xylist[0]
920
+ y0 = yc = -xylist[1]
921
+ dlist.append(['MoveToPoint', (x0, y0), {}])
922
+ elif op == 'l': # draw line
923
+ x2 = xylist[0]
924
+ y2 = -xylist[1]
925
+ dlist.append(['AddLineToPoint', (x2, y2), {}])
926
+ xc = x2
927
+ yc = y2
928
+ elif op == 're': # draw rectangle
929
+ x = xylist[0]
930
+ y = -xylist[1]
931
+ w = xylist[2]
932
+ h = xylist[3]
933
+ retuple = (x, y-h, w, h)
934
+ if h < 0.0:
935
+ retuple = (x, y, w, -h)
936
+ dlist.append(['AddRectangle', retuple, {}])
937
+ elif op in ('c', 'v', 'y'): # draw Bezier curve
938
+ args = []
939
+ if op == 'v':
940
+ args.extend([xc, yc])
941
+ args.extend([xylist[0], -xylist[1],
942
+ xylist[2], -xylist[3]])
943
+ if op == 'y':
944
+ args.extend([xylist[2], -xylist[3]])
945
+ if op == 'c':
946
+ args.extend([xylist[4], -xylist[5]])
947
+ dlist.append(['AddCurveToPoint', args, {}])
948
+ elif op == 'h':
949
+ dlist.append(['CloseSubpath', (), {}])
950
+ dlist.append(['DrawPath', ('GraphicsPath', rule), {}])
951
+ return dlist
952
+
953
+ def InsertXObject(self, name):
954
+ """
955
+ XObject can be an image or a 'form' (an arbitrary PDF sequence).
956
+ """
957
+ dlist = []
958
+ xobject = self.page["/Resources"].getObject()['/XObject']
959
+ stream = xobject[name]
960
+ if stream.get('/Subtype') == '/Form':
961
+ # insert contents into current page drawing
962
+ if not name in self.formdrawings: # extract if not already done
963
+ pdf_fonts = self.FetchFonts(stream)
964
+ x_bbox = stream.get('/BBox')
965
+ matrix = stream.get('/Matrix')
966
+ form_ops = ContentStream(stream, self.pdfdoc).operations
967
+ oplist = [([], 'q'), (matrix, 'cm')] # push state & apply matrix
968
+ oplist.extend(form_ops) # add form contents
969
+ oplist.append(([], 'Q')) # restore original state
970
+ self.formdrawings[name] = self.ProcessOperators(oplist, pdf_fonts)
971
+ dlist.extend(self.formdrawings[name])
972
+ elif stream.get('/Subtype') == '/Image':
973
+ width = stream['/Width']
974
+ height = stream['/Height']
975
+ x_depth = stream['/BitsPerComponent']
976
+ filters = stream["/Filter"]
977
+ item = self.AddBitmap(stream._data, width, height, filters)
978
+ if item: # may be unimplemented
979
+ dlist.append(item)
980
+ return dlist
981
+
982
+ def InlineImage(self, operand):
983
+ """ operand contains an image"""
984
+ dlist = []
985
+ data = operand.get('data')
986
+ settings = operand.get('settings')
987
+ width = settings['/W']
988
+ height = settings['/H']
989
+ x_depth = settings['/BPC']
990
+ filters = settings['/F']
991
+ item = self.AddBitmap(data, width, height, filters)
992
+ if item: # may be unimplemented
993
+ dlist.append(item)
994
+ return dlist
995
+
996
+ def AddBitmap(self, data, width, height, filters):
997
+ """
998
+ Add wx.Bitmap from data, processed by filters.
999
+ """
1000
+ if '/A85' in filters or '/ASCII85Decode' in filters:
1001
+ data = ASCII85Decode.decode(data)
1002
+ if '/Fl' in filters or '/FlateDecode' in filters:
1003
+ data = FlateDecode.decode(data, None)
1004
+ if '/CCF' in filters or '/CCITTFaxDecode' in filters:
1005
+ if VERBOSE:
1006
+ print('PDF operation /CCITTFaxDecode is not implemented')
1007
+ return []
1008
+ if '/DCT' in filters or '/DCTDecode' in filters:
1009
+ stream = BytesIO(data)
1010
+ image = wx.Image(stream, wx.BITMAP_TYPE_JPEG)
1011
+ bitmap = wx.Bitmap(image)
1012
+ else:
1013
+ try:
1014
+ bitmap = wx.Bitmap.FromBuffer(width, height, data)
1015
+ except:
1016
+ return [] # any error
1017
+ return ['DrawBitmap', (bitmap, 0, 0-height, width, height), {}]
1018
+
1019
+ def ConvertCMYK(self, operand):
1020
+ """
1021
+ Convert CMYK values (0 to 1.0) in operand to nearest RGB.
1022
+ """
1023
+ c, m, y, k = operand
1024
+ r = round((1-c)*(1-k)*255)
1025
+ b = round((1-y)*(1-k)*255)
1026
+ g = round((1-m)*(1-k)*255)
1027
+ return (r, g, b)
1028
+
1029
+ #----------------------------------------------------------------------------
1030
+
1031
+ class pdfState(object):
1032
+ """
1033
+ Instance holds the current pdf graphics and text state. It can be
1034
+ saved (pushed) and restored (popped) by the owning parent
1035
+ """
1036
+ def __init__ (self):
1037
+ """
1038
+ Creates an instance with default values. Individual attributes
1039
+ are modified directly not via getters and setters
1040
+ """
1041
+ self.lineWidth = 1.0
1042
+ self.lineCapStyle = wx.CAP_BUTT
1043
+ self.lineJoinStyle = wx.JOIN_MITER
1044
+ self.lineDashArray = []
1045
+ self.lineDashPhase = 0
1046
+ self.miterLimit = None
1047
+ self.strokeRGB = wx.BLACK
1048
+ self.fillRGB = wx.BLACK # used for both shapes & text
1049
+ self.fillMode = None
1050
+
1051
+ self.textMatrix = [1, 0, 0, 1, 0, 0]
1052
+ self.textLineMatrix = [1, 0, 0, 1, 0, 0]
1053
+ self.charSpacing = 0
1054
+ self.wordSpacing = 0
1055
+ self.horizontalScaling = None
1056
+ self.leading = None
1057
+ self.font = None
1058
+ self.fontSize = None
1059
+ self.textRenderMode = None
1060
+ self.textRise = 0
1061
+
1062
+ #------------------------------------------------------------------------------
1063
+
1064
+ class pdfPrintout(wx.Printout):
1065
+ """
1066
+ Class encapsulating the functionality of printing out the document. The methods below
1067
+ over-ride those of the base class and supply document-specific information to the
1068
+ printing framework that calls them internally.
1069
+ """
1070
+ def __init__(self, title, view):
1071
+ """
1072
+ Pass in the instance of dpViewer to be printed.
1073
+ """
1074
+ wx.Printout.__init__(self, title)
1075
+ self.view = view
1076
+
1077
+ def HasPage(self, pageno):
1078
+ """
1079
+ Report whether pageno exists.
1080
+ """
1081
+ if pageno <= self.view.numpages:
1082
+ return True
1083
+ else:
1084
+ return False
1085
+
1086
+ def GetPageInfo(self):
1087
+ """
1088
+ Supply maximum range of pages and the range to be printed
1089
+ These are initial values passed to Printer dialog, where they
1090
+ can be amended by user.
1091
+ """
1092
+ maxnum = self.view.numpages
1093
+ return (1, maxnum, 1, maxnum)
1094
+
1095
+ def OnPrintPage(self, page):
1096
+ """
1097
+ Provide the data for page by rendering the drawing commands
1098
+ to the printer DC, MuPDF returns the page content from an internally
1099
+ generated bitmap and sfac sets it to a high enough resolution that
1100
+ reduces anti-aliasing blur but keeps it small to minimise printing time
1101
+ """
1102
+ sfac = 1.0
1103
+ if mupdf:
1104
+ sfac = 4.0
1105
+ pageno = page - 1 # zero based
1106
+ width = self.view.pagesizes[pageno][0]
1107
+ height = self.view.pagesizes[pageno][1]
1108
+ self.FitThisSizeToPage(wx.Size(int(width*sfac), int(height*sfac)))
1109
+ dc = self.GetDC()
1110
+ gc = wx.GraphicsContext.Create(dc)
1111
+ if not mupdf:
1112
+ gc.Translate(0, height)
1113
+ if wx.PlatformInfo[1] == 'wxMSW' and have_cairo:
1114
+ device_scale = wx.ClientDC(self.view).GetPPI()[0]/72.0 # pixels per inch/ppi
1115
+ gc.font_scale = 1.0 / device_scale
1116
+
1117
+ self.view.pdfdoc.RenderPage(gc, pageno, sfac)
1118
+ return True