scitex 2.7.0__py3-none-any.whl → 2.7.3__py3-none-any.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 (297) hide show
  1. scitex/__init__.py +6 -2
  2. scitex/__version__.py +1 -1
  3. scitex/audio/README.md +52 -0
  4. scitex/audio/__init__.py +384 -0
  5. scitex/audio/__main__.py +129 -0
  6. scitex/audio/_tts.py +334 -0
  7. scitex/audio/engines/__init__.py +44 -0
  8. scitex/audio/engines/base.py +275 -0
  9. scitex/audio/engines/elevenlabs_engine.py +143 -0
  10. scitex/audio/engines/gtts_engine.py +162 -0
  11. scitex/audio/engines/pyttsx3_engine.py +131 -0
  12. scitex/audio/mcp_server.py +757 -0
  13. scitex/bridge/_helpers.py +1 -1
  14. scitex/bridge/_plt_vis.py +1 -1
  15. scitex/bridge/_stats_vis.py +1 -1
  16. scitex/dev/plt/__init__.py +272 -0
  17. scitex/dev/plt/plot_mpl_axhline.py +28 -0
  18. scitex/dev/plt/plot_mpl_axhspan.py +28 -0
  19. scitex/dev/plt/plot_mpl_axvline.py +28 -0
  20. scitex/dev/plt/plot_mpl_axvspan.py +28 -0
  21. scitex/dev/plt/plot_mpl_bar.py +29 -0
  22. scitex/dev/plt/plot_mpl_barh.py +29 -0
  23. scitex/dev/plt/plot_mpl_boxplot.py +28 -0
  24. scitex/dev/plt/plot_mpl_contour.py +31 -0
  25. scitex/dev/plt/plot_mpl_contourf.py +31 -0
  26. scitex/dev/plt/plot_mpl_errorbar.py +30 -0
  27. scitex/dev/plt/plot_mpl_eventplot.py +28 -0
  28. scitex/dev/plt/plot_mpl_fill.py +30 -0
  29. scitex/dev/plt/plot_mpl_fill_between.py +31 -0
  30. scitex/dev/plt/plot_mpl_hexbin.py +28 -0
  31. scitex/dev/plt/plot_mpl_hist.py +28 -0
  32. scitex/dev/plt/plot_mpl_hist2d.py +28 -0
  33. scitex/dev/plt/plot_mpl_imshow.py +29 -0
  34. scitex/dev/plt/plot_mpl_pcolormesh.py +31 -0
  35. scitex/dev/plt/plot_mpl_pie.py +29 -0
  36. scitex/dev/plt/plot_mpl_plot.py +29 -0
  37. scitex/dev/plt/plot_mpl_quiver.py +31 -0
  38. scitex/dev/plt/plot_mpl_scatter.py +28 -0
  39. scitex/dev/plt/plot_mpl_stackplot.py +31 -0
  40. scitex/dev/plt/plot_mpl_stem.py +29 -0
  41. scitex/dev/plt/plot_mpl_step.py +29 -0
  42. scitex/dev/plt/plot_mpl_violinplot.py +28 -0
  43. scitex/dev/plt/plot_sns_barplot.py +29 -0
  44. scitex/dev/plt/plot_sns_boxplot.py +29 -0
  45. scitex/dev/plt/plot_sns_heatmap.py +28 -0
  46. scitex/dev/plt/plot_sns_histplot.py +29 -0
  47. scitex/dev/plt/plot_sns_kdeplot.py +29 -0
  48. scitex/dev/plt/plot_sns_lineplot.py +31 -0
  49. scitex/dev/plt/plot_sns_scatterplot.py +29 -0
  50. scitex/dev/plt/plot_sns_stripplot.py +29 -0
  51. scitex/dev/plt/plot_sns_swarmplot.py +29 -0
  52. scitex/dev/plt/plot_sns_violinplot.py +29 -0
  53. scitex/dev/plt/plot_stx_bar.py +29 -0
  54. scitex/dev/plt/plot_stx_barh.py +29 -0
  55. scitex/dev/plt/plot_stx_box.py +28 -0
  56. scitex/dev/plt/plot_stx_boxplot.py +28 -0
  57. scitex/dev/plt/plot_stx_conf_mat.py +28 -0
  58. scitex/dev/plt/plot_stx_contour.py +31 -0
  59. scitex/dev/plt/plot_stx_ecdf.py +28 -0
  60. scitex/dev/plt/plot_stx_errorbar.py +30 -0
  61. scitex/dev/plt/plot_stx_fill_between.py +31 -0
  62. scitex/dev/plt/plot_stx_fillv.py +28 -0
  63. scitex/dev/plt/plot_stx_heatmap.py +28 -0
  64. scitex/dev/plt/plot_stx_image.py +28 -0
  65. scitex/dev/plt/plot_stx_imshow.py +28 -0
  66. scitex/dev/plt/plot_stx_joyplot.py +28 -0
  67. scitex/dev/plt/plot_stx_kde.py +28 -0
  68. scitex/dev/plt/plot_stx_line.py +28 -0
  69. scitex/dev/plt/plot_stx_mean_ci.py +28 -0
  70. scitex/dev/plt/plot_stx_mean_std.py +28 -0
  71. scitex/dev/plt/plot_stx_median_iqr.py +28 -0
  72. scitex/dev/plt/plot_stx_raster.py +28 -0
  73. scitex/dev/plt/plot_stx_rectangle.py +28 -0
  74. scitex/dev/plt/plot_stx_scatter.py +29 -0
  75. scitex/dev/plt/plot_stx_shaded_line.py +29 -0
  76. scitex/dev/plt/plot_stx_violin.py +28 -0
  77. scitex/dev/plt/plot_stx_violinplot.py +28 -0
  78. scitex/fig/__init__.py +352 -0
  79. scitex/{vis → fig}/backend/_parser.py +1 -1
  80. scitex/{vis → fig}/canvas.py +1 -1
  81. scitex/{vis → fig}/editor/_defaults.py +70 -5
  82. scitex/fig/editor/_edit.py +751 -0
  83. scitex/{vis → fig}/editor/_qt_editor.py +181 -1
  84. scitex/fig/editor/flask_editor/_bbox.py +1276 -0
  85. scitex/fig/editor/flask_editor/_core.py +624 -0
  86. scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
  87. scitex/fig/editor/flask_editor/_renderer.py +739 -0
  88. scitex/{vis → fig}/editor/flask_editor/templates/__init__.py +1 -1
  89. scitex/fig/editor/flask_editor/templates/_html.py +834 -0
  90. scitex/fig/editor/flask_editor/templates/_scripts.py +3136 -0
  91. scitex/{vis → fig}/editor/flask_editor/templates/_styles.py +625 -18
  92. scitex/{vis → fig}/io/__init__.py +13 -1
  93. scitex/fig/io/_bundle.py +973 -0
  94. scitex/{vis → fig}/io/_canvas.py +1 -1
  95. scitex/{vis → fig}/io/_data.py +1 -1
  96. scitex/{vis → fig}/io/_export.py +1 -1
  97. scitex/{vis → fig}/io/_load.py +1 -1
  98. scitex/{vis → fig}/io/_panel.py +1 -1
  99. scitex/{vis → fig}/io/_save.py +1 -1
  100. scitex/{vis → fig}/model/__init__.py +1 -1
  101. scitex/{vis → fig}/model/_annotations.py +1 -1
  102. scitex/{vis → fig}/model/_axes.py +1 -1
  103. scitex/{vis → fig}/model/_figure.py +1 -1
  104. scitex/{vis → fig}/model/_guides.py +1 -1
  105. scitex/{vis → fig}/model/_plot.py +1 -1
  106. scitex/{vis → fig}/model/_styles.py +1 -1
  107. scitex/{vis → fig}/utils/__init__.py +1 -1
  108. scitex/io/__init__.py +10 -26
  109. scitex/io/_bundle.py +434 -0
  110. scitex/io/_flush.py +5 -2
  111. scitex/io/_load.py +98 -0
  112. scitex/io/_load_modules/_H5Explorer.py +5 -2
  113. scitex/io/_load_modules/_canvas.py +2 -2
  114. scitex/io/_load_modules/_image.py +3 -4
  115. scitex/io/_load_modules/_txt.py +4 -2
  116. scitex/io/_metadata.py +34 -324
  117. scitex/io/_metadata_modules/__init__.py +46 -0
  118. scitex/io/_metadata_modules/_embed.py +70 -0
  119. scitex/io/_metadata_modules/_read.py +64 -0
  120. scitex/io/_metadata_modules/_utils.py +79 -0
  121. scitex/io/_metadata_modules/embed_metadata_jpeg.py +74 -0
  122. scitex/io/_metadata_modules/embed_metadata_pdf.py +53 -0
  123. scitex/io/_metadata_modules/embed_metadata_png.py +26 -0
  124. scitex/io/_metadata_modules/embed_metadata_svg.py +62 -0
  125. scitex/io/_metadata_modules/read_metadata_jpeg.py +57 -0
  126. scitex/io/_metadata_modules/read_metadata_pdf.py +51 -0
  127. scitex/io/_metadata_modules/read_metadata_png.py +39 -0
  128. scitex/io/_metadata_modules/read_metadata_svg.py +44 -0
  129. scitex/io/_qr_utils.py +5 -3
  130. scitex/io/_save.py +548 -30
  131. scitex/io/_save_modules/_canvas.py +3 -3
  132. scitex/io/_save_modules/_image.py +5 -9
  133. scitex/io/_save_modules/_tex.py +7 -4
  134. scitex/io/utils/h5_to_zarr.py +11 -9
  135. scitex/msword/__init__.py +255 -0
  136. scitex/msword/profiles.py +357 -0
  137. scitex/msword/reader.py +753 -0
  138. scitex/msword/utils.py +289 -0
  139. scitex/msword/writer.py +362 -0
  140. scitex/plt/__init__.py +5 -2
  141. scitex/plt/_subplots/_AxesWrapper.py +6 -6
  142. scitex/plt/_subplots/_AxisWrapper.py +15 -9
  143. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +36 -0
  144. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +264 -0
  145. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +213 -0
  146. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +128 -0
  147. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +59 -0
  148. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +34 -0
  149. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +593 -0
  150. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +654 -0
  151. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +527 -0
  152. scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +321 -0
  153. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +33 -0
  154. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +152 -0
  155. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +600 -0
  156. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +79 -5
  157. scitex/plt/_subplots/_FigWrapper.py +6 -6
  158. scitex/plt/_subplots/_SubplotsWrapper.py +28 -18
  159. scitex/plt/_subplots/_export_as_csv.py +35 -5
  160. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +8 -0
  161. scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +10 -21
  162. scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +18 -7
  163. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +28 -12
  164. scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +10 -4
  165. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +13 -1
  166. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +12 -2
  167. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +10 -3
  168. scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -4
  169. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +18 -3
  170. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +44 -36
  171. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +14 -2
  172. scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +11 -5
  173. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +84 -0
  174. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +85 -0
  175. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +14 -3
  176. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_contour.py +54 -0
  177. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +14 -2
  178. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +120 -0
  179. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +16 -6
  180. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +29 -19
  181. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_imshow.py +63 -0
  182. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +22 -5
  183. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +18 -14
  184. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +18 -14
  185. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +18 -14
  186. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +10 -2
  187. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +51 -0
  188. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +18 -9
  189. scitex/plt/ax/_plot/_stx_ecdf.py +4 -2
  190. scitex/plt/gallery/_generate.py +421 -14
  191. scitex/plt/io/__init__.py +53 -0
  192. scitex/plt/io/_bundle.py +490 -0
  193. scitex/plt/io/_layered_bundle.py +1343 -0
  194. scitex/plt/styles/SCITEX_STYLE.yaml +26 -0
  195. scitex/plt/styles/__init__.py +14 -0
  196. scitex/plt/styles/presets.py +78 -0
  197. scitex/plt/utils/__init__.py +13 -1
  198. scitex/plt/utils/_collect_figure_metadata.py +10 -14
  199. scitex/plt/utils/_configure_mpl.py +6 -18
  200. scitex/plt/utils/_crop.py +32 -14
  201. scitex/plt/utils/_csv_column_naming.py +54 -0
  202. scitex/plt/utils/_figure_mm.py +116 -1
  203. scitex/plt/utils/_hitmap.py +1643 -0
  204. scitex/plt/utils/metadata/__init__.py +25 -0
  205. scitex/plt/utils/metadata/_core.py +9 -10
  206. scitex/plt/utils/metadata/_dimensions.py +6 -3
  207. scitex/plt/utils/metadata/_editable_export.py +405 -0
  208. scitex/plt/utils/metadata/_geometry_extraction.py +570 -0
  209. scitex/schema/__init__.py +109 -16
  210. scitex/schema/_canvas.py +1 -1
  211. scitex/schema/_plot.py +1015 -0
  212. scitex/schema/_stats.py +2 -2
  213. scitex/stats/__init__.py +117 -0
  214. scitex/stats/io/__init__.py +29 -0
  215. scitex/stats/io/_bundle.py +156 -0
  216. scitex/tex/__init__.py +4 -0
  217. scitex/tex/_export.py +890 -0
  218. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/METADATA +11 -1
  219. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/RECORD +238 -170
  220. scitex/io/memo.md +0 -2827
  221. scitex/plt/REQUESTS.md +0 -191
  222. scitex/plt/_subplots/TODO.md +0 -53
  223. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +0 -559
  224. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +0 -1609
  225. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +0 -447
  226. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +0 -110
  227. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +0 -88
  228. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +0 -103
  229. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +0 -106
  230. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +0 -92
  231. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +0 -92
  232. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +0 -92
  233. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +0 -84
  234. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +0 -84
  235. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +0 -83
  236. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +0 -93
  237. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +0 -91
  238. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +0 -91
  239. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +0 -91
  240. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +0 -97
  241. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +0 -98
  242. scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +0 -84
  243. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +0 -101
  244. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +0 -96
  245. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +0 -95
  246. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +0 -95
  247. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +0 -93
  248. scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +0 -95
  249. scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +0 -95
  250. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +0 -83
  251. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +0 -92
  252. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +0 -121
  253. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +0 -84
  254. scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +0 -110
  255. scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +0 -92
  256. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +0 -95
  257. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +0 -96
  258. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +0 -95
  259. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +0 -95
  260. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +0 -92
  261. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +0 -84
  262. scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +0 -94
  263. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +0 -109
  264. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +0 -108
  265. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +0 -93
  266. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +0 -84
  267. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +0 -96
  268. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +0 -96
  269. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +0 -96
  270. scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +0 -99
  271. scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +0 -100
  272. scitex/vis/__init__.py +0 -177
  273. scitex/vis/editor/_edit.py +0 -390
  274. scitex/vis/editor/flask_editor/_bbox.py +0 -529
  275. scitex/vis/editor/flask_editor/_core.py +0 -168
  276. scitex/vis/editor/flask_editor/_renderer.py +0 -393
  277. scitex/vis/editor/flask_editor/templates/_html.py +0 -513
  278. scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
  279. /scitex/{vis → fig}/README.md +0 -0
  280. /scitex/{vis → fig}/backend/__init__.py +0 -0
  281. /scitex/{vis → fig}/backend/_export.py +0 -0
  282. /scitex/{vis → fig}/backend/_render.py +0 -0
  283. /scitex/{vis → fig}/docs/CANVAS_ARCHITECTURE.md +0 -0
  284. /scitex/{vis → fig}/editor/__init__.py +0 -0
  285. /scitex/{vis → fig}/editor/_dearpygui_editor.py +0 -0
  286. /scitex/{vis → fig}/editor/_flask_editor.py +0 -0
  287. /scitex/{vis → fig}/editor/_mpl_editor.py +0 -0
  288. /scitex/{vis → fig}/editor/_tkinter_editor.py +0 -0
  289. /scitex/{vis → fig}/editor/flask_editor/__init__.py +0 -0
  290. /scitex/{vis → fig}/editor/flask_editor/_utils.py +0 -0
  291. /scitex/{vis → fig}/io/_directory.py +0 -0
  292. /scitex/{vis → fig}/model/_plot_types.py +0 -0
  293. /scitex/{vis → fig}/utils/_defaults.py +0 -0
  294. /scitex/{vis → fig}/utils/_validate.py +0 -0
  295. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/WHEEL +0 -0
  296. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/entry_points.txt +0 -0
  297. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata_modules/_read.py
4
+
5
+ """Main read_metadata dispatcher."""
6
+
7
+ import os
8
+ from typing import Any, Dict, Optional
9
+
10
+
11
+ def read_metadata(image_path: str) -> Optional[Dict[str, Any]]:
12
+ """
13
+ Read metadata from an image or PDF file.
14
+
15
+ Args:
16
+ image_path: Path to the file (PNG, JPEG, SVG, or PDF)
17
+
18
+ Returns:
19
+ Dictionary containing metadata, or None if no metadata found
20
+
21
+ Raises:
22
+ FileNotFoundError: If file doesn't exist
23
+ ValueError: If file format is not supported
24
+
25
+ Example:
26
+ >>> metadata = read_metadata('result.png')
27
+ >>> print(metadata['experiment'])
28
+ 'seizure_prediction_001'
29
+ >>> metadata = read_metadata('result.pdf')
30
+ """
31
+ if not os.path.exists(image_path):
32
+ raise FileNotFoundError(f"File not found: {image_path}")
33
+
34
+ path_lower = image_path.lower()
35
+
36
+ # Dispatch to format-specific handlers
37
+ if path_lower.endswith(".png"):
38
+ from .read_metadata_png import read_metadata_png
39
+
40
+ return read_metadata_png(image_path)
41
+
42
+ elif path_lower.endswith((".jpg", ".jpeg")):
43
+ from .read_metadata_jpeg import read_metadata_jpeg
44
+
45
+ return read_metadata_jpeg(image_path)
46
+
47
+ elif path_lower.endswith(".svg"):
48
+ from .read_metadata_svg import read_metadata_svg
49
+
50
+ return read_metadata_svg(image_path)
51
+
52
+ elif path_lower.endswith(".pdf"):
53
+ from .read_metadata_pdf import read_metadata_pdf
54
+
55
+ return read_metadata_pdf(image_path)
56
+
57
+ else:
58
+ raise ValueError(
59
+ f"Unsupported file format: {image_path}. "
60
+ "Only PNG, JPEG, SVG, and PDF formats are supported."
61
+ )
62
+
63
+
64
+ # EOF
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata/_utils.py
4
+
5
+ """Shared utilities for metadata handling."""
6
+
7
+ import json
8
+ from typing import Any, Dict
9
+
10
+
11
+ def convert_for_json(obj: Any) -> Any:
12
+ """
13
+ Convert non-JSON-serializable objects to serializable format.
14
+
15
+ Handles FixedFloat objects from figure metadata by converting
16
+ them to regular floats.
17
+ """
18
+ # Handle FixedFloat (from _collect_figure_metadata)
19
+ if (
20
+ hasattr(obj, "value")
21
+ and hasattr(obj, "precision")
22
+ and hasattr(obj, "__class__")
23
+ and obj.__class__.__name__ == "FixedFloat"
24
+ ):
25
+ return obj.value
26
+
27
+ # Handle dict recursively
28
+ if isinstance(obj, dict):
29
+ return {key: convert_for_json(value) for key, value in obj.items()}
30
+
31
+ # Handle list recursively
32
+ if isinstance(obj, list):
33
+ return [convert_for_json(item) for item in obj]
34
+
35
+ # Handle tuple
36
+ if isinstance(obj, tuple):
37
+ return [convert_for_json(item) for item in obj]
38
+
39
+ # Handle numpy arrays
40
+ if hasattr(obj, "tolist"):
41
+ return obj.tolist()
42
+
43
+ # Default: return as-is
44
+ return obj
45
+
46
+
47
+ def serialize_metadata(metadata: Dict[str, Any]) -> str:
48
+ """Serialize metadata to JSON string."""
49
+ metadata = convert_for_json(metadata)
50
+ try:
51
+ return json.dumps(metadata, ensure_ascii=False, indent=2)
52
+ except (TypeError, ValueError) as e:
53
+ raise ValueError(f"Metadata must be JSON serializable: {e}")
54
+
55
+
56
+ def has_metadata(image_path: str) -> bool:
57
+ """
58
+ Check if an image file has embedded metadata.
59
+
60
+ Args:
61
+ image_path: Path to the image file
62
+
63
+ Returns:
64
+ True if metadata exists, False otherwise
65
+
66
+ Example:
67
+ >>> if has_metadata('result.png'):
68
+ ... print(read_metadata('result.png'))
69
+ """
70
+ from ._read import read_metadata
71
+
72
+ try:
73
+ metadata = read_metadata(image_path)
74
+ return metadata is not None
75
+ except:
76
+ return False
77
+
78
+
79
+ # EOF
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata/embed_metadata_jpeg.py
4
+
5
+ """JPEG metadata embedding using EXIF ImageDescription field."""
6
+
7
+ from PIL import Image
8
+
9
+
10
+ def embed_metadata_jpeg(image_path: str, metadata_json: str) -> None:
11
+ """
12
+ Embed metadata into a JPEG file using EXIF ImageDescription field.
13
+
14
+ Args:
15
+ image_path: Path to the JPEG file.
16
+ metadata_json: JSON string of metadata to embed.
17
+
18
+ Raises:
19
+ ImportError: If piexif is not installed.
20
+ """
21
+ try:
22
+ import piexif
23
+ except ImportError:
24
+ raise ImportError(
25
+ "piexif is required for JPEG metadata support. "
26
+ "Install with: pip install piexif"
27
+ )
28
+
29
+ img = Image.open(image_path)
30
+
31
+ # Convert to RGB if necessary (JPEG doesn't support RGBA)
32
+ if img.mode in ("RGBA", "LA", "P"):
33
+ rgb_img = Image.new("RGB", img.size, (255, 255, 255))
34
+ if img.mode == "P":
35
+ img = img.convert("RGBA")
36
+ if img.mode in ("RGBA", "LA"):
37
+ rgb_img.paste(img, mask=img.split()[-1])
38
+ else:
39
+ rgb_img.paste(img)
40
+ img = rgb_img
41
+
42
+ # Create EXIF dict with metadata in ImageDescription field
43
+ exif_dict = {
44
+ "0th": {piexif.ImageIFD.ImageDescription: metadata_json.encode("utf-8")},
45
+ "Exif": {},
46
+ "GPS": {},
47
+ "1st": {},
48
+ }
49
+
50
+ # Try to preserve existing EXIF data
51
+ try:
52
+ existing_exif = piexif.load(img.info.get("exif", b""))
53
+ # Merge with new metadata (prioritize new metadata)
54
+ for ifd in ["Exif", "GPS", "1st"]:
55
+ if ifd in existing_exif:
56
+ exif_dict[ifd].update(existing_exif[ifd])
57
+ except:
58
+ pass # If existing EXIF is corrupted, just use new metadata
59
+
60
+ exif_bytes = piexif.dump(exif_dict)
61
+
62
+ # Save with EXIF metadata (quality=100 for maximum quality)
63
+ img.save(
64
+ image_path,
65
+ "JPEG",
66
+ quality=100,
67
+ subsampling=0,
68
+ optimize=False,
69
+ exif=exif_bytes,
70
+ )
71
+ img.close()
72
+
73
+
74
+ # EOF
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata_modules/embed_metadata_pdf.py
4
+
5
+ """PDF metadata embedding using PDF Info Dictionary."""
6
+
7
+
8
+ def embed_metadata_pdf(image_path: str, metadata_json: str, metadata: dict) -> None:
9
+ """
10
+ Embed metadata into a PDF file using PDF Info Dictionary.
11
+
12
+ Args:
13
+ image_path: Path to the PDF file.
14
+ metadata_json: JSON string of metadata to embed.
15
+ metadata: Original metadata dict for extracting title/author.
16
+
17
+ Raises:
18
+ ImportError: If pypdf is not installed.
19
+ """
20
+ try:
21
+ from pypdf import PdfReader, PdfWriter
22
+ except ImportError:
23
+ raise ImportError(
24
+ "pypdf is required for PDF metadata support. "
25
+ "Install with: pip install pypdf"
26
+ )
27
+
28
+ # Read existing PDF
29
+ reader = PdfReader(image_path)
30
+ writer = PdfWriter()
31
+
32
+ # Copy all pages
33
+ for page in reader.pages:
34
+ writer.add_page(page)
35
+
36
+ # Prepare metadata for PDF Info Dictionary
37
+ pdf_metadata = {
38
+ "/Title": metadata.get("title", ""),
39
+ "/Author": metadata.get("author", ""),
40
+ "/Subject": metadata_json, # Store full JSON in Subject field
41
+ "/Creator": "SciTeX",
42
+ "/Producer": "SciTeX",
43
+ }
44
+
45
+ # Add metadata
46
+ writer.add_metadata(pdf_metadata)
47
+
48
+ # Write back to file
49
+ with open(image_path, "wb") as output_file:
50
+ writer.write(output_file)
51
+
52
+
53
+ # EOF
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata/embed_metadata_png.py
4
+
5
+ """PNG metadata embedding using tEXt chunks."""
6
+
7
+ from PIL import Image
8
+ from PIL.PngImagePlugin import PngInfo
9
+
10
+
11
+ def embed_metadata_png(image_path: str, metadata_json: str) -> None:
12
+ """
13
+ Embed metadata into a PNG file using tEXt chunks.
14
+
15
+ Args:
16
+ image_path: Path to the PNG file.
17
+ metadata_json: JSON string of metadata to embed.
18
+ """
19
+ img = Image.open(image_path)
20
+ pnginfo = PngInfo()
21
+ pnginfo.add_text("scitex_metadata", metadata_json)
22
+ img.save(image_path, "PNG", pnginfo=pnginfo)
23
+ img.close()
24
+
25
+
26
+ # EOF
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata_modules/embed_metadata_svg.py
4
+
5
+ """SVG metadata embedding using <metadata> element."""
6
+
7
+ import re
8
+
9
+
10
+ def embed_metadata_svg(image_path: str, metadata_json: str) -> None:
11
+ """
12
+ Embed metadata into an SVG file using <metadata> element.
13
+
14
+ Args:
15
+ image_path: Path to the SVG file.
16
+ metadata_json: JSON string of metadata to embed.
17
+
18
+ Raises:
19
+ ValueError: If the SVG file is invalid.
20
+ """
21
+ with open(image_path, "r", encoding="utf-8") as f:
22
+ svg_content = f.read()
23
+
24
+ # Remove existing scitex metadata if present
25
+ svg_content = re.sub(
26
+ r'<metadata[^>]*id="scitex_metadata"[^>]*>.*?</metadata>',
27
+ "",
28
+ svg_content,
29
+ flags=re.DOTALL,
30
+ )
31
+
32
+ # Find the opening <svg> tag and insert metadata after it
33
+ svg_match = re.search(r"(<svg[^>]*>)", svg_content)
34
+ if svg_match:
35
+ svg_tag_end = svg_match.end()
36
+ # Create metadata element with scitex data
37
+ metadata_element = (
38
+ f'\n<metadata id="scitex_metadata">'
39
+ f"<scitex:data>{metadata_json}</scitex:data>"
40
+ f"</metadata>\n"
41
+ )
42
+ svg_content = (
43
+ svg_content[:svg_tag_end]
44
+ + metadata_element
45
+ + svg_content[svg_tag_end:]
46
+ )
47
+
48
+ # Ensure scitex namespace is declared in svg tag if not present
49
+ if "xmlns:scitex" not in svg_content:
50
+ svg_content = svg_content.replace(
51
+ "<svg",
52
+ '<svg xmlns:scitex="http://scitex.io/metadata"',
53
+ 1,
54
+ )
55
+
56
+ with open(image_path, "w", encoding="utf-8") as f:
57
+ f.write(svg_content)
58
+ else:
59
+ raise ValueError(f"Invalid SVG file: {image_path}")
60
+
61
+
62
+ # EOF
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata_modules/read_metadata_jpeg.py
4
+
5
+ """JPEG metadata reading from EXIF ImageDescription field."""
6
+
7
+ import json
8
+ from typing import Any, Dict, Optional
9
+
10
+ from PIL import Image
11
+
12
+
13
+ def read_metadata_jpeg(image_path: str) -> Optional[Dict[str, Any]]:
14
+ """
15
+ Read metadata from a JPEG file.
16
+
17
+ Args:
18
+ image_path: Path to the JPEG file.
19
+
20
+ Returns:
21
+ Dictionary containing metadata, or None if no metadata found.
22
+ """
23
+ metadata = None
24
+ img = Image.open(image_path)
25
+ try:
26
+ try:
27
+ import piexif
28
+
29
+ # Load EXIF data
30
+ if "exif" in img.info:
31
+ exif_dict = piexif.load(img.info["exif"])
32
+
33
+ # Try to read ImageDescription field
34
+ if piexif.ImageIFD.ImageDescription in exif_dict.get("0th", {}):
35
+ description = exif_dict["0th"][piexif.ImageIFD.ImageDescription]
36
+
37
+ # Decode bytes to string
38
+ if isinstance(description, bytes):
39
+ description = description.decode("utf-8", errors="ignore")
40
+
41
+ # Try to parse as JSON
42
+ try:
43
+ metadata = json.loads(description)
44
+ except json.JSONDecodeError:
45
+ # If not JSON, return as raw text
46
+ metadata = {"raw": description}
47
+ except ImportError:
48
+ pass # piexif not available, return None
49
+ except Exception:
50
+ pass # EXIF data corrupted or not readable
51
+ finally:
52
+ img.close()
53
+
54
+ return metadata
55
+
56
+
57
+ # EOF
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata_modules/read_metadata_pdf.py
4
+
5
+ """PDF metadata reading from PDF Info Dictionary."""
6
+
7
+ import json
8
+ from typing import Any, Dict, Optional
9
+
10
+
11
+ def read_metadata_pdf(image_path: str) -> Optional[Dict[str, Any]]:
12
+ """
13
+ Read metadata from a PDF file.
14
+
15
+ Args:
16
+ image_path: Path to the PDF file.
17
+
18
+ Returns:
19
+ Dictionary containing metadata, or None if no metadata found.
20
+ """
21
+ metadata = None
22
+
23
+ try:
24
+ from pypdf import PdfReader
25
+
26
+ reader = PdfReader(image_path)
27
+
28
+ # Try to read metadata from PDF Info Dictionary
29
+ if reader.metadata:
30
+ # Check Subject field for JSON metadata
31
+ if "/Subject" in reader.metadata:
32
+ subject = reader.metadata["/Subject"]
33
+ try:
34
+ metadata = json.loads(subject)
35
+ except json.JSONDecodeError:
36
+ # If not JSON, create metadata dict from available fields
37
+ metadata = {
38
+ "title": reader.metadata.get("/Title", ""),
39
+ "author": reader.metadata.get("/Author", ""),
40
+ "subject": subject,
41
+ "creator": reader.metadata.get("/Creator", ""),
42
+ }
43
+ except ImportError:
44
+ pass # pypdf not available, return None
45
+ except Exception:
46
+ pass # PDF metadata corrupted or not readable
47
+
48
+ return metadata
49
+
50
+
51
+ # EOF
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata_modules/read_metadata_png.py
4
+
5
+ """PNG metadata reading from tEXt chunks."""
6
+
7
+ import json
8
+ from typing import Any, Dict, Optional
9
+
10
+ from PIL import Image
11
+
12
+
13
+ def read_metadata_png(image_path: str) -> Optional[Dict[str, Any]]:
14
+ """
15
+ Read metadata from a PNG file.
16
+
17
+ Args:
18
+ image_path: Path to the PNG file.
19
+
20
+ Returns:
21
+ Dictionary containing metadata, or None if no metadata found.
22
+ """
23
+ metadata = None
24
+ img = Image.open(image_path)
25
+ try:
26
+ if hasattr(img, "info") and "scitex_metadata" in img.info:
27
+ metadata_json = img.info["scitex_metadata"]
28
+ try:
29
+ metadata = json.loads(metadata_json)
30
+ except json.JSONDecodeError:
31
+ # Metadata exists but is not valid JSON
32
+ metadata = {"raw": metadata_json}
33
+ finally:
34
+ img.close()
35
+
36
+ return metadata
37
+
38
+
39
+ # EOF
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_metadata_modules/read_metadata_svg.py
4
+
5
+ """SVG metadata reading from <metadata> element."""
6
+
7
+ import json
8
+ import re
9
+ from typing import Any, Dict, Optional
10
+
11
+
12
+ def read_metadata_svg(image_path: str) -> Optional[Dict[str, Any]]:
13
+ """
14
+ Read metadata from an SVG file.
15
+
16
+ Args:
17
+ image_path: Path to the SVG file.
18
+
19
+ Returns:
20
+ Dictionary containing metadata, or None if no metadata found.
21
+ """
22
+ metadata = None
23
+
24
+ with open(image_path, "r", encoding="utf-8") as f:
25
+ svg_content = f.read()
26
+
27
+ # Look for scitex metadata element
28
+ match = re.search(
29
+ r'<metadata[^>]*id="scitex_metadata"[^>]*>.*?'
30
+ r"<scitex:data>(.*?)</scitex:data>.*?</metadata>",
31
+ svg_content,
32
+ flags=re.DOTALL,
33
+ )
34
+ if match:
35
+ metadata_json = match.group(1)
36
+ try:
37
+ metadata = json.loads(metadata_json)
38
+ except json.JSONDecodeError:
39
+ metadata = {"raw": metadata_json}
40
+
41
+ return metadata
42
+
43
+
44
+ # EOF
scitex/io/_qr_utils.py CHANGED
@@ -9,9 +9,13 @@ import json
9
9
  import os
10
10
  from pathlib import Path
11
11
 
12
+ from scitex import logging
13
+
12
14
  __FILE__ = __file__
13
15
  __DIR__ = os.path.dirname(__FILE__)
14
16
 
17
+ logger = logging.getLogger(__name__)
18
+
15
19
 
16
20
  def add_qr_to_figure(fig, metadata, position="bottom-right", size=0.08):
17
21
  """
@@ -30,9 +34,7 @@ def add_qr_to_figure(fig, metadata, position="bottom-right", size=0.08):
30
34
  import qrcode
31
35
  from PIL import Image as PILImage
32
36
  except ImportError:
33
- import warnings
34
-
35
- warnings.warn(
37
+ logger.warning(
36
38
  "qrcode library not available. Install with: pip install qrcode[pil]"
37
39
  )
38
40
  return fig