{"id":1310,"date":"2026-11-06T12:14:09","date_gmt":"2026-11-06T20:14:09","guid":{"rendered":"https:\/\/salemdata.net\/johnpress\/?p=1310"},"modified":"2026-11-06T12:14:09","modified_gmt":"2026-11-06T20:14:09","slug":"local-ai-pdf-digestion","status":"publish","type":"post","link":"https:\/\/salemdata.net\/johnpress\/?p=1310","title":{"rendered":"Local AI: PDF Digestion"},"content":{"rendered":"<div class=\"gfmr-markdown-container\"><div class=\"gfmr-markdown-source\" style=\"display: none;\">&lt;h1&gt;Introduction&lt;\/h1&gt;\n&lt;p&gt;My local AI, the &lt;a href=&quot;https:\/\/github.com\/Niko1221\/Strata&quot;&gt;Strata&lt;\/a&gt; project model &lt;strong&gt;qwen3.8-flash-next-iq3_s,&lt;\/strong&gt; does not accept PDFs for upload.&lt;\/p&gt;\n&lt;img class=&quot; wp-image-1320&quot; src=&quot;https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/20261106_095014_Fri.png&quot; alt=&quot;&quot; width=&quot;346&quot; height=&quot;218&quot; \/&gt; Strata Chat Interface\n&lt;p&gt;The interface &lt;em&gt;does&lt;\/em&gt; accept binary images.\u00a0 So if I want my chat to consider the contents of a PDF, I have to extract its text and images and then upload the text and images to my local chat.\u00a0 This study compares two tools that can be used for what I call &#8220;digestion&#8221; of PDF files: 1) &lt;strong&gt;pymupdf&lt;\/strong&gt; and 2) &lt;strong&gt;docling&lt;\/strong&gt;&lt;\/p&gt;\n&lt;h1&gt;Methodology&lt;\/h1&gt;\n&lt;p&gt;Since special libraries and AI models are needed, I created separate Python environments so we know what additional packages are needed and what space they consume.\u00a0 When I installed docling, I was surprised &#8212; it looks like another AI model is staged for the docling process.&lt;\/p&gt;\n&lt;h2&gt;Libraries&lt;\/h2&gt;\n&lt;p&gt;Installing either library will consume appreciable disk space.\u00a0 Notably, Docling could contribute as much as 9 GB.&lt;\/p&gt;\n&lt;h2&gt;Setting Up the Python Environments&lt;\/h2&gt;\n&lt;h3&gt;pymupdf&lt;\/h3&gt;\n&lt;blockquote&gt;\n&lt;pre&gt;jlpoole@ryzdesk ~ $ python3 -m venv ~\/venvs\/pymu\r\njlpoole@ryzdesk ~ $ du -s ~\/venvs\/pymu\r\n13380 \/home\/jlpoole\/venvs\/pymu\r\njlpoole@ryzdesk ~ $ du -sh ~\/venvs\/pymu\r\n14M \/home\/jlpoole\/venvs\/pymu\r\njlpoole@ryzdesk ~ $\r\n&lt;\/pre&gt;\n&lt;\/blockquote&gt;\n&lt;h3&gt;docling&lt;\/h3&gt;\n&lt;blockquote&gt;\n&lt;pre&gt;jlpoole@ryzdesk ~ $ python3 -m venv ~\/venvs\/docling\r\njlpoole@ryzdesk ~ $ du -sh ~\/venvs\/docling\/\r\n14M     \/home\/jlpoole\/venvs\/docling\/\r\njlpoole@ryzdesk ~ $&lt;\/pre&gt;\n&lt;\/blockquote&gt;\n&lt;h3&gt;Updated disk-space accounting&lt;\/h3&gt;\n&lt;table&gt;\n&lt;thead&gt;\n&lt;tr&gt;\n&lt;th&gt;Component&lt;\/th&gt;\n&lt;th&gt;PyMuPDF&lt;\/th&gt;\n&lt;th&gt;Docling&lt;\/th&gt;\n&lt;\/tr&gt;\n&lt;\/thead&gt;\n&lt;tbody&gt;\n&lt;tr&gt;\n&lt;td&gt;Initial virtual environment&lt;\/td&gt;\n&lt;td&gt;14 MiB&lt;\/td&gt;\n&lt;td&gt;14 MiB&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;tr&gt;\n&lt;td&gt;Installed virtual environment&lt;\/td&gt;\n&lt;td&gt;294 MiB&lt;\/td&gt;\n&lt;td&gt;6.2 GiB&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;tr&gt;\n&lt;td&gt;Increase over baseline&lt;\/td&gt;\n&lt;td&gt;~280 MiB&lt;\/td&gt;\n&lt;td&gt;~6.19 GiB&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;tr&gt;\n&lt;td&gt;Hugging Face model weights&lt;\/td&gt;\n&lt;td&gt;\u2014&lt;\/td&gt;\n&lt;td&gt;506 MiB&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;tr&gt;\n&lt;td&gt;Recently modified pip cache&lt;\/td&gt;\n&lt;td&gt;Not yet apportioned&lt;\/td&gt;\n&lt;td&gt;3,169.61 MiB (shared)&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;\/tbody&gt;\n&lt;\/table&gt;\n&lt;p&gt;If we provisionally attribute all 3,169.61 MiB of recently modified pip cache files to Docling, the combined footprint would be approximately 9.8 GiB, including the environment growth, model weights, and cached downloads.\u00a0\u00a0That figure is an upper-bound-style estimate, not a verified total: some cached packages may belong to PyMuPDF or other pip activity.&lt;\/p&gt;\n&lt;h2&gt;Test PDFs&lt;\/h2&gt;\n&lt;p&gt;I&#8217;m using these two PDFs since they contain lots of details in formats other than text that could be relevant to an AI&#8217;s analysis.&lt;\/p&gt;\n&lt;ul&gt;\n&lt;li&gt;Sensirion specifications for its transducer &lt;a title=&quot;https:\/\/www.digikey.com\/en\/products\/detail\/sensirion-ag\/SDP810-125PA\/6605488?s=N4IgTCBcDaIMoBEAKAOAjABgLRrAViQEMQBdAXyA&quot; href=&quot;https:\/\/www.digikey.com\/en\/products\/detail\/sensirion-ag\/SDP810-125PA\/6605488?s=N4IgTCBcDaIMoBEAKAOAjABgLRrAViQEMQBdAXyA&quot; data-from-md=&quot;&quot;&gt;SDP810-125PA&lt;\/a&gt;&lt;\/li&gt;\n&lt;li&gt;&#8220;Implementation, Characterization, and Evaluation of an Inexpensive&lt;br \/&gt;\nLow-Power Low-Noise Infrasound Sensor Based on a Micromachined&lt;br \/&gt;\nDifferential Pressure Transducer and a Mechanical Filter&#8221; (2012)<span id='easy-footnote-1-1310' class='easy-footnote-margin-adjust'><\/span><span class='easy-footnote'><a href='https:\/\/salemdata.net\/johnpress\/?p=1310#easy-footnote-bottom-1-1310' title='&amp;lt;\/p&amp;gt;\n&amp;lt;div id=&amp;quot;refs&amp;quot; class=&amp;quot;references csl-bib-body hanging-indent&amp;quot; role=&amp;quot;list&amp;quot;&amp;gt;\n&amp;lt;div id=&amp;quot;ref-ImplementationCharacterizationandEvaluationofanInexpensiveLowPowerLowNoiseInfrasoundSensorBasedonaMicromachinedDifferentialPressureTransducerandaMechanicalFilter&amp;quot; class=&amp;quot;csl-entry&amp;quot; role=&amp;quot;listitem&amp;quot;&amp;gt;Marcillo, Omar, Jeffrey B. Johnson, and Darren Hart. 2012.&amp;lt;br \/&amp;gt;\n\u201cImplementation, Characterization, and Evaluation of an&amp;lt;br \/&amp;gt;\nInexpensive Low-Power Low-Noise Infrasound Sensor Based on a&amp;lt;br \/&amp;gt;\nMicromachined Differential Pressure Transducer and a Mechanical&amp;lt;br \/&amp;gt;\nFilter.\u201d &amp;lt;em&amp;gt;Journal of Atmospheric and Oceanic Technology&amp;lt;\/em&amp;gt;&amp;lt;br \/&amp;gt;\n(Boston MA, USA) 29 (9): 1275\u201384. &amp;lt;a href=&amp;quot;https:\/\/doi.org\/10.1175\/JTECH-D-11-00101.1&amp;quot;&amp;gt;https:\/\/doi.org\/10.1175\/JTECH-D-11-00101.1&amp;lt;\/a&amp;gt;.&amp;lt;\/div&amp;gt;\n&amp;lt;\/div&amp;gt;\n&amp;lt;p&amp;gt;'><sup>1<\/sup><\/a><\/span>&lt;\/li&gt;\n&lt;\/ul&gt;\n&lt;h2&gt;Results&lt;\/h2&gt;\n&lt;h3&gt;Commands&lt;\/h3&gt;\n&lt;p&gt;The command for the pymupdf is this script:&lt;\/p&gt;\n&lt;blockquote&gt;\n&lt;pre&gt;import fitz # PyMuPDF\r\nimport os\r\n\r\ndoc = fitz.open(&quot;ABC.pdf&quot;)\r\nos.makedirs(&quot;output_images&quot;, exist_ok=True)\r\n\r\n# 1. Extract all text\r\nwith open(&quot;extracted_text.txt&quot;, &quot;w&quot;, encoding=&quot;utf-8&quot;) as f:\r\nfor page_num in range(len(doc)):\r\npage = doc[page_num]\r\nf.write(f&quot;--- Page {page_num + 1} ---\\n&quot;)\r\nf.write(page.get_text())\r\n\r\n# 2. Extract all embedded images\r\nimage_count = 0\r\nfor page_num in range(len(doc)):\r\npage = doc[page_num]\r\nfor img_index, img in enumerate(page.get_images(full=True)):\r\nxref = img[0]\r\nbase_image = doc.extract_image(xref)\r\nimage_bytes = base_image[&quot;image&quot;]\r\nimage_ext = base_image[&quot;ext&quot;]\r\nimage_filename = f&quot;output_images\/page_{page_num + 1}_img_{image_index}.{image_ext}&quot;\r\nwith open(image_filename, &quot;wb&quot;) as img_file:\r\nimg_file.write(image_bytes)\r\nimage_count += 1\r\n\r\nprint(f&quot;Extracted text to extracted_text.txt and {image_count} images to output_images\/&quot;)\r\njlpoole@ryzdesk ~\/work\/HDC\/pdftrial\/pymupdf $ cat &gt;install.sh&lt;\/pre&gt;\n&lt;\/blockquote&gt;\n&lt;p&gt;The command for the docling is simply:&lt;\/p&gt;\n&lt;blockquote&gt;\n&lt;pre&gt;docling ABC.pdf --to md --image-export-mode referenced --output output_dir\/&lt;\/pre&gt;\n&lt;\/blockquote&gt;\n&lt;h3&gt;Extractions Results&lt;\/h3&gt;\n&lt;h4&gt;text extractions&lt;\/h4&gt;\n&lt;h5&gt;pymupdf&lt;\/h5&gt;\n&lt;p&gt;Johnson Study &#8211; pymupdf (&lt;a href=&quot;https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/pymupdf_johnson_extracted_text.txt&quot;&gt;text&lt;\/a&gt;)&lt;\/p&gt;\n&lt;p&gt;Sensirion specification &#8211; pymupdf (&lt;a href=&quot;https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/pymupdf_sensirion_extracted_text.txt&quot;&gt;text&lt;\/a&gt;)&lt;\/p&gt;\n&lt;h5&gt;docling&lt;\/h5&gt;\n&lt;p&gt;Johnson Study &#8211; docling (&lt;a href=&quot;https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/docling_Johnson.md&quot;&gt;markdown&lt;\/a&gt;)&lt;\/p&gt;\n&lt;p&gt;Sensirion specification &#8211; docling (&lt;a href=&quot;https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/docling_sensirion.md&quot;&gt;markdown&lt;\/a&gt;)&lt;\/p&gt;\n&lt;h4&gt;proof sheets of the image extractions&lt;\/h4&gt;\n&lt;p&gt;&lt;&lt;\/p&gt;\n&lt;table&gt;\n&lt;tbody&gt;\n&lt;tr&gt;\n&lt;td&gt;&lt;\/td&gt;\n&lt;td&gt;&lt;strong&gt;Johnson PDF&lt;\/strong&gt;&lt;\/td&gt;\n&lt;td&gt;&lt;strong&gt;Sensirion PDF&lt;\/strong&gt;&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;tr&gt;\n&lt;td&gt;&lt;strong&gt;pymupdf&lt;\/strong&gt;&lt;\/td&gt;\n&lt;td&gt;\n&lt;p&gt;&lt;img class=&quot; wp-image-1314&quot; src=&quot;https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/johnson_output_images_proof_sheet_20261106_082149.png&quot; alt=&quot;&quot; width=&quot;345&quot; height=&quot;180&quot; \/&gt; pymupdf Johnson&lt;\/td&gt;\n&lt;td&gt;\n&lt;p&gt;&lt;img class=&quot; wp-image-1315&quot; src=&quot;https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_artifacts_proof_sheet_20261106_082432.png&quot; alt=&quot;&quot; width=&quot;237&quot; height=&quot;270&quot; \/&gt; pymupdf Sensirion&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;tr&gt;\n&lt;td&gt;&lt;strong&gt;docling&lt;\/strong&gt;&lt;\/td&gt;\n&lt;td&gt;\n&lt;p&gt;&lt;img class=&quot; wp-image-1316&quot; src=&quot;https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/Johnson__artifacts_proof_sheet_20261106_082344.png&quot; alt=&quot;&quot; width=&quot;342&quot; height=&quot;249&quot; \/&gt; docling Johnson&lt;\/td&gt;\n&lt;td&gt;\n&lt;p&gt;&lt;img class=&quot; wp-image-1313&quot; src=&quot;https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_output_images_proof_sheet_20261106_082240.png&quot; alt=&quot;&quot; width=&quot;328&quot; height=&quot;644&quot; \/&gt; docling Sensirion&lt;\/td&gt;\n&lt;\/tr&gt;\n&lt;\/tbody&gt;\n&lt;\/table&gt;\n&lt;h3&gt;Local AI Chats Analyses Base On A Particular Extraction&lt;\/h3&gt;\n&lt;p&gt;pymupdf-based chat\u00a0 &lt;a href=&quot;https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/pymufpdf_strata-chat-2026-11-06-08-49.md&quot;&gt;pymufpdf_strata-chat-2026-11-06-08-49.md&lt;\/a&gt;&lt;\/p&gt;\n&lt;p&gt;docling-based chat &lt;a href=&quot;https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/docling_strata-chat-2026-11-06-09-04.md&quot;&gt;docling_strata-chat-2026-11-06-09-04.md&lt;\/a&gt;&lt;\/p&gt;\n&lt;h3&gt;Analysis Of Both Chats&lt;\/h3&gt;\n&lt;p&gt;Local AI Analysis of its pymupdf and docling responses &lt;a href=&quot;https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/Analysis_of_both_chats_strata-chat-2026-11-06-17-21.md&quot;&gt;Analysis_of_both_chats_strata-chat-2026-11-06-17-21.md&lt;\/a&gt;&lt;\/p&gt;\n&lt;h1&gt;Conclusion&lt;\/h1&gt;\n&lt;p&gt;Definitely go with the &lt;strong&gt;docling&lt;\/strong&gt;.\u00a0 For technical PDFs that contain tables and graphs, you want the benefit of that information being digested for AI.&lt;\/p&gt;\n<\/div><div class=\"gfmr-markdown-rendered\"><h1>Introduction<\/h1>\n<p>My local AI, the <a href=\"https:\/\/github.com\/Niko1221\/Strata\">Strata<\/a> project model <strong>qwen3.8-flash-next-iq3_s,<\/strong> does not accept PDFs for upload.<\/p>\n<figure id=\"attachment_1320\" aria-describedby=\"caption-attachment-1320\" style=\"width: 346px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1320\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/20261106_095014_Fri.png\" alt=\"\" width=\"346\" height=\"218\" srcset=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/20261106_095014_Fri.png 956w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/20261106_095014_Fri-300x189.png 300w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/20261106_095014_Fri-768x484.png 768w\" sizes=\"auto, (max-width: 346px) 100vw, 346px\" \/><figcaption id=\"caption-attachment-1320\" class=\"wp-caption-text\">Strata Chat Interface<\/figcaption><\/figure>\n<p>The interface <em>does<\/em> accept binary images.\u00a0 So if I want my chat to consider the contents of a PDF, I have to extract its text and images and then upload the text and images to my local chat.\u00a0 This study compares two tools that can be used for what I call &#8220;digestion&#8221; of PDF files: 1) <strong>pymupdf<\/strong> and 2) <strong>docling<\/strong><\/p>\n<h1>Methodology<\/h1>\n<p>Since special libraries and AI models are needed, I created separate Python environments so we know what additional packages are needed and what space they consume.\u00a0 When I installed docling, I was surprised &#8212; it looks like another AI model is staged for the docling process.<\/p>\n<h2>Libraries<\/h2>\n<p>Installing either library will consume appreciable disk space.\u00a0 Notably, Docling could contribute as much as 9 GB.<\/p>\n<h2>Setting Up the Python Environments<\/h2>\n<h3>pymupdf<\/h3>\n<blockquote>\n<pre>jlpoole@ryzdesk ~ $ python3 -m venv ~\/venvs\/pymu\r\njlpoole@ryzdesk ~ $ du -s ~\/venvs\/pymu\r\n13380 \/home\/jlpoole\/venvs\/pymu\r\njlpoole@ryzdesk ~ $ du -sh ~\/venvs\/pymu\r\n14M \/home\/jlpoole\/venvs\/pymu\r\njlpoole@ryzdesk ~ $\r\n<\/pre>\n<\/blockquote>\n<h3>docling<\/h3>\n<blockquote>\n<pre>jlpoole@ryzdesk ~ $ python3 -m venv ~\/venvs\/docling\r\njlpoole@ryzdesk ~ $ du -sh ~\/venvs\/docling\/\r\n14M     \/home\/jlpoole\/venvs\/docling\/\r\njlpoole@ryzdesk ~ $<\/pre>\n<\/blockquote>\n<h3>Updated disk-space accounting<\/h3>\n<table>\n<thead>\n<tr>\n<th>Component<\/th>\n<th>PyMuPDF<\/th>\n<th>Docling<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Initial virtual environment<\/td>\n<td>14 MiB<\/td>\n<td>14 MiB<\/td>\n<\/tr>\n<tr>\n<td>Installed virtual environment<\/td>\n<td>294 MiB<\/td>\n<td>6.2 GiB<\/td>\n<\/tr>\n<tr>\n<td>Increase over baseline<\/td>\n<td>~280 MiB<\/td>\n<td>~6.19 GiB<\/td>\n<\/tr>\n<tr>\n<td>Hugging Face model weights<\/td>\n<td>\u2014<\/td>\n<td>506 MiB<\/td>\n<\/tr>\n<tr>\n<td>Recently modified pip cache<\/td>\n<td>Not yet apportioned<\/td>\n<td>3,169.61 MiB (shared)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If we provisionally attribute all 3,169.61 MiB of recently modified pip cache files to Docling, the combined footprint would be approximately 9.8 GiB, including the environment growth, model weights, and cached downloads.\u00a0\u00a0That figure is an upper-bound-style estimate, not a verified total: some cached packages may belong to PyMuPDF or other pip activity.<\/p>\n<h2>Test PDFs<\/h2>\n<p>I&#8217;m using these two PDFs since they contain lots of details in formats other than text that could be relevant to an AI&#8217;s analysis.<\/p>\n<ul>\n<li>Sensirion specifications for its transducer <a title=\"https:\/\/www.digikey.com\/en\/products\/detail\/sensirion-ag\/SDP810-125PA\/6605488?s=N4IgTCBcDaIMoBEAKAOAjABgLRrAViQEMQBdAXyA\" href=\"https:\/\/www.digikey.com\/en\/products\/detail\/sensirion-ag\/SDP810-125PA\/6605488?s=N4IgTCBcDaIMoBEAKAOAjABgLRrAViQEMQBdAXyA\" data-from-md=\"\">SDP810-125PA<\/a><\/li>\n<li>&#8220;Implementation, Characterization, and Evaluation of an Inexpensive<br \/>\nLow-Power Low-Noise Infrasound Sensor Based on a Micromachined<br \/>\nDifferential Pressure Transducer and a Mechanical Filter&#8221; (2012)<span id='easy-footnote-2-1310' class='easy-footnote-margin-adjust'><\/span><span class='easy-footnote'><a href='https:\/\/salemdata.net\/johnpress\/?p=1310#easy-footnote-bottom-2-1310' title='&lt;\/p&gt;\n&lt;div id=&quot;refs&quot; class=&quot;references csl-bib-body hanging-indent&quot; role=&quot;list&quot;&gt;\n&lt;div id=&quot;ref-ImplementationCharacterizationandEvaluationofanInexpensiveLowPowerLowNoiseInfrasoundSensorBasedonaMicromachinedDifferentialPressureTransducerandaMechanicalFilter&quot; class=&quot;csl-entry&quot; role=&quot;listitem&quot;&gt;Marcillo, Omar, Jeffrey B. Johnson, and Darren Hart. 2012.&lt;br \/&gt;\n\u201cImplementation, Characterization, and Evaluation of an&lt;br \/&gt;\nInexpensive Low-Power Low-Noise Infrasound Sensor Based on a&lt;br \/&gt;\nMicromachined Differential Pressure Transducer and a Mechanical&lt;br \/&gt;\nFilter.\u201d &lt;em&gt;Journal of Atmospheric and Oceanic Technology&lt;\/em&gt;&lt;br \/&gt;\n(Boston MA, USA) 29 (9): 1275\u201384. &lt;a href=&quot;https:\/\/doi.org\/10.1175\/JTECH-D-11-00101.1&quot;&gt;https:\/\/doi.org\/10.1175\/JTECH-D-11-00101.1&lt;\/a&gt;.&lt;\/div&gt;\n&lt;\/div&gt;\n&lt;p&gt;'><sup>2<\/sup><\/a><\/span><\/li>\n<\/ul>\n<h2>Results<\/h2>\n<h3>Commands<\/h3>\n<p>The command for the pymupdf is this script:<\/p>\n<blockquote>\n<pre>import fitz # PyMuPDF\r\nimport os\r\n\r\ndoc = fitz.open(\"ABC.pdf\")\r\nos.makedirs(\"output_images\", exist_ok=True)\r\n\r\n# 1. Extract all text\r\nwith open(\"extracted_text.txt\", \"w\", encoding=\"utf-8\") as f:\r\nfor page_num in range(len(doc)):\r\npage = doc[page_num]\r\nf.write(f\"--- Page {page_num + 1} ---\\n\")\r\nf.write(page.get_text())\r\n\r\n# 2. Extract all embedded images\r\nimage_count = 0\r\nfor page_num in range(len(doc)):\r\npage = doc[page_num]\r\nfor img_index, img in enumerate(page.get_images(full=True)):\r\nxref = img[0]\r\nbase_image = doc.extract_image(xref)\r\nimage_bytes = base_image[\"image\"]\r\nimage_ext = base_image[\"ext\"]\r\nimage_filename = f\"output_images\/page_{page_num + 1}_img_{image_index}.{image_ext}\"\r\nwith open(image_filename, \"wb\") as img_file:\r\nimg_file.write(image_bytes)\r\nimage_count += 1\r\n\r\nprint(f\"Extracted text to extracted_text.txt and {image_count} images to output_images\/\")\r\njlpoole@ryzdesk ~\/work\/HDC\/pdftrial\/pymupdf $ cat &gt;install.sh<\/pre>\n<\/blockquote>\n<p>The command for the docling is simply:<\/p>\n<blockquote>\n<pre>docling ABC.pdf --to md --image-export-mode referenced --output output_dir\/<\/pre>\n<\/blockquote>\n<h3>Extractions Results<\/h3>\n<h4>text extractions<\/h4>\n<h5>pymupdf<\/h5>\n<p>Johnson Study &#8211; pymupdf (<a href=\"https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/pymupdf_johnson_extracted_text.txt\">text<\/a>)<\/p>\n<p>Sensirion specification &#8211; pymupdf (<a href=\"https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/pymupdf_sensirion_extracted_text.txt\">text<\/a>)<\/p>\n<h5>docling<\/h5>\n<p>Johnson Study &#8211; docling (<a href=\"https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/docling_Johnson.md\">markdown<\/a>)<\/p>\n<p>Sensirion specification &#8211; docling (<a href=\"https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/docling_sensirion.md\">markdown<\/a>)<\/p>\n<h4>proof sheets of the image extractions<\/h4>\n<p>&lt;<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td><strong>Johnson PDF<\/strong><\/td>\n<td><strong>Sensirion PDF<\/strong><\/td>\n<\/tr>\n<tr>\n<td><strong>pymupdf<\/strong><\/td>\n<td>\n<p><figure id=\"attachment_1314\" aria-describedby=\"caption-attachment-1314\" style=\"width: 345px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1314\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/johnson_output_images_proof_sheet_20261106_082149.png\" alt=\"\" width=\"345\" height=\"180\" srcset=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/johnson_output_images_proof_sheet_20261106_082149.png 834w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/johnson_output_images_proof_sheet_20261106_082149-300x156.png 300w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/johnson_output_images_proof_sheet_20261106_082149-768x401.png 768w\" sizes=\"auto, (max-width: 345px) 100vw, 345px\" \/><figcaption id=\"caption-attachment-1314\" class=\"wp-caption-text\">pymupdf Johnson<\/figcaption><\/figure><\/td>\n<td>\n<p><figure id=\"attachment_1315\" aria-describedby=\"caption-attachment-1315\" style=\"width: 237px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1315\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_artifacts_proof_sheet_20261106_082432.png\" alt=\"\" width=\"237\" height=\"270\" srcset=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_artifacts_proof_sheet_20261106_082432.png 834w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_artifacts_proof_sheet_20261106_082432-263x300.png 263w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_artifacts_proof_sheet_20261106_082432-768x876.png 768w\" sizes=\"auto, (max-width: 237px) 100vw, 237px\" \/><figcaption id=\"caption-attachment-1315\" class=\"wp-caption-text\">pymupdf Sensirion<\/figcaption><\/figure><\/td>\n<\/tr>\n<tr>\n<td><strong>docling<\/strong><\/td>\n<td>\n<p><figure id=\"attachment_1316\" aria-describedby=\"caption-attachment-1316\" style=\"width: 342px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1316\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/Johnson__artifacts_proof_sheet_20261106_082344.png\" alt=\"\" width=\"342\" height=\"249\" srcset=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/Johnson__artifacts_proof_sheet_20261106_082344.png 834w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/Johnson__artifacts_proof_sheet_20261106_082344-300x218.png 300w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/Johnson__artifacts_proof_sheet_20261106_082344-768x559.png 768w\" sizes=\"auto, (max-width: 342px) 100vw, 342px\" \/><figcaption id=\"caption-attachment-1316\" class=\"wp-caption-text\">docling Johnson<\/figcaption><\/figure><\/td>\n<td>\n<p><figure id=\"attachment_1313\" aria-describedby=\"caption-attachment-1313\" style=\"width: 328px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1313\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_output_images_proof_sheet_20261106_082240.png\" alt=\"\" width=\"328\" height=\"644\" srcset=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_output_images_proof_sheet_20261106_082240.png 834w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_output_images_proof_sheet_20261106_082240-153x300.png 153w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_output_images_proof_sheet_20261106_082240-814x1600.png 814w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_output_images_proof_sheet_20261106_082240-768x1509.png 768w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/11\/sensirion_output_images_proof_sheet_20261106_082240-782x1536.png 782w\" sizes=\"auto, (max-width: 328px) 100vw, 328px\" \/><figcaption id=\"caption-attachment-1313\" class=\"wp-caption-text\">docling Sensirion<\/figcaption><\/figure><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Local AI Chats Analyses Base On A Particular Extraction<\/h3>\n<p>pymupdf-based chat\u00a0 <a href=\"https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/pymufpdf_strata-chat-2026-11-06-08-49.md\">pymufpdf_strata-chat-2026-11-06-08-49.md<\/a><\/p>\n<p>docling-based chat <a href=\"https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/docling_strata-chat-2026-11-06-09-04.md\">docling_strata-chat-2026-11-06-09-04.md<\/a><\/p>\n<h3>Analysis Of Both Chats<\/h3>\n<p>Local AI Analysis of its pymupdf and docling responses <a href=\"https:\/\/salemdata.net\/dev\/wp\/pdf_digesters\/Analysis_of_both_chats_strata-chat-2026-11-06-17-21.md\">Analysis_of_both_chats_strata-chat-2026-11-06-17-21.md<\/a><\/p>\n<h1>Conclusion<\/h1>\n<p>Definitely go with the <strong>docling<\/strong>.\u00a0 For technical PDFs that contain tables and graphs, you want the benefit of that information being digested for AI.<\/p>\n<\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>&lt;h1&gt;Introduction&lt;\/h1&gt; &lt;p&gt;My local AI, the &lt;a href=&quot;https:\/\/github.com\/Niko1221\/Strata&quot;&gt;Strata&lt;\/a&gt; project model &lt;strong&gt;qwen3.8-flash-next-iq3_s,&lt;\/strong&gt; does not accept PDFs for upload.&lt;\/p&gt; &lt;p&gt;The interface &lt;em&gt;does&lt;\/em&gt; accept binary images.\u00a0 So if I want my chat to consider the contents of a PDF, I have to extract its text and images and then upload the text and images to my local chat.\u00a0 This [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_gfmr_meta_descriptions":[],"_gfmr_multilingual_taxonomy_terms":[],"footnotes":""},"categories":[37,147,1],"tags":[],"class_list":["post-1310","post","type-post","status-publish","format-standard","hentry","category-ai","category-local","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts\/1310","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1310"}],"version-history":[{"count":10,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts\/1310\/revisions"}],"predecessor-version":[{"id":1327,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts\/1310\/revisions\/1327"}],"wp:attachment":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1310"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1310"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1310"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}