krutiextract 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KrutiExtract Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: krutiextract
3
+ Version: 1.0.0
4
+ Summary: A universal toolkit for extracting legacy Hindi PDFs (KrutiDev/Devlys/Chanakya) to Markdown
5
+ Author-email: "Bharat Choudhary (Lecturer, Department of Secondary Education, Govt. of Rajasthan)" <epicbharat@gmail.com>
6
+ Project-URL: Homepage, https://github.com/epicbharat
7
+ Project-URL: Bug Tracker, https://github.com/epicbharat/krutiextract/issues
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Text Processing :: Linguistic
12
+ Classifier: Natural Language :: Hindi
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: pymupdf
17
+ Requires-Dist: pymupdf4llm
18
+ Requires-Dist: nltk
19
+ Requires-Dist: opencv-python-headless
20
+ Requires-Dist: numpy
21
+ Dynamic: license-file
22
+
23
+ <div align="center">
24
+ <img src="assets/logo.png" alt="KrutiExtract Logo" width="200"/>
25
+ <h1>KrutiExtract</h1>
26
+ <p><strong>A Universal Legacy Hindi PDF to Markdown Extractor</strong></p>
27
+
28
+ [![Python Version](https://img.shields.io/badge/python-3.8%2B-blue)](https://www.python.org/)
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
30
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/epicbharat)
31
+ </div>
32
+
33
+ <hr/>
34
+
35
+ Extracting legacy Hindi fonts (like **KrutiDev**, **Devlys**, or **Chanakya**) from PDF documents has traditionally been a nightmare. Standard OCR and PDF text extractors read characters based on visual coordinates. Because Hindi matras (vowel marks like `ि` or `े`) overlap with consonants, this visual sorting scrambles the text (e.g., typing `vkSj` for 'और' gets extracted as `vkjS`, breaking the conversion into the nonsense word 'आरै').
36
+
37
+ **KrutiExtract** solves this problem by bypassing visual coordinate sorting and extracting the **logical character stream** directly from the PDF.
38
+
39
+ ## ✨ Core Features
40
+
41
+ - **Perfect Character Order:** Preserves the original typist's keystrokes, completely avoiding spatial scrambling of matras.
42
+ - **Smart Auto-Detect Engine:** Automatically mathematically calculates text frequencies to detect whether the typist used **KrutiDev / Devlys** or **Chanakya**, instantly routing the text to the correct translation engine!
43
+ - **English / Hinglish Bypass Mode:** If the engine detects that the document contains modern Unicode Hindi, standard English, or Hinglish, it automatically bypasses legacy conversion entirely—perfectly preserving your modern texts!
44
+ - **Dynamic English Preservation:** Uses NLTK's English corpus to proactively detect and protect English words, numbers, acronyms, and HTML tags interspersed within mixed-font Hindi texts.
45
+ - **Collision-Free Safe-Tokens:** Markdown syntax elements (like `#` or `*`) clash with KrutiDev maps. KrutiExtract shields these structural elements using a unique `$$$INDEX$$$` safe-token system during font conversion.
46
+
47
+ ## 👁️ Advanced OCR & Image Cleaning
48
+
49
+ When the toolkit encounters text trapped inside a scanned image, it seamlessly hands it over to **Tesseract OCR** in the background.
50
+
51
+ - **Native Hindi OCR:** The toolkit hardcodes `ocr_language="hin"` into the internal pipeline. This permanently stops Tesseract from trying to hallucinate English letters onto Hindi image shapes, ensuring natively output Unicode Devanagari.
52
+ - **OpenCV Image Cleaning (`--enhance-ocr`):** Pass this flag to activate our built-in computer vision pipeline. The toolkit will automatically intercept blurry images in the PDF, upscale the resolution, apply unsharp masking, and run adaptive thresholding to perfectly reconstruct the text shapes *before* OCR scans it!
53
+
54
+ ## 🚀 Installation
55
+
56
+ Ensure you have Python 3.8+ installed.
57
+
58
+ ```bash
59
+ # Clone the repository
60
+ git clone https://github.com/epicbharat/krutiextract.git
61
+ cd krutiextract
62
+
63
+ # Create and activate a virtual environment (Recommended)
64
+ python -m venv venv
65
+ venv\Scripts\activate # On Windows
66
+ # source venv/bin/activate # On macOS/Linux
67
+
68
+ # Install dependencies
69
+ pip install -r requirements.txt
70
+
71
+ # Download the required NLTK English word corpus
72
+ python -c "import nltk; nltk.download('words')"
73
+ ```
74
+
75
+ ### Note on Tesseract (Required for OCR)
76
+ If you are parsing scanned PDFs or PDFs with embedded images, you must have [Tesseract OCR](https://github.com/tesseract-ocr/tesseract) installed on your system.
77
+ - **Windows:** Download the installer and ensure you check the **"Hindi"** language pack during installation. Add Tesseract to your PATH.
78
+ - **Linux:** `sudo apt-get install tesseract-ocr tesseract-ocr-hin`
79
+
80
+ ## 💻 CLI Usage Guide
81
+
82
+ KrutiExtract provides a powerful Command Line Interface (CLI).
83
+
84
+ ### 1. Process a Single File
85
+ ```bash
86
+ python -m src.cli --input "path/to/document.pdf" --output "path/to/output.md"
87
+ ```
88
+
89
+ ### 2. Batch Process a Directory
90
+ Recursively process an entire folder of PDFs:
91
+ ```bash
92
+ python -m src.cli --dir "path/to/pdf/folder" --out-dir "path/to/markdown/folder"
93
+ ```
94
+
95
+ ### 3. Force a Specific Font Encoding
96
+ By default, the font is set to `auto`. You can force a specific bypass or mapping:
97
+ ```bash
98
+ # Available options: krutidev, chanakya, auto, unicode, english
99
+ python -m src.cli --input "doc.pdf" --font chanakya
100
+ ```
101
+
102
+ ### 4. Enable OpenCV OCR Enhancement
103
+ Use this flag for old, blurry, or low-resolution scanned PDFs to artificially sharpen the text before extraction:
104
+ ```bash
105
+ python -m src.cli --input "blurry_scan.pdf" --enhance-ocr
106
+ ```
107
+
108
+ ## 🤝 Contributing
109
+
110
+ Contributions are welcome! If you find a PDF that breaks the extraction logic or a rare character combination we missed, please open an issue and attach the sample PDF.
111
+
112
+ ## 📄 License
113
+
114
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
115
+
116
+ ---
117
+ **Author:** Bharat Choudhary (Lecturer, Department of Secondary Education, Govt. of Rajasthan)
118
+ **Email:** epicbharat@gmail.com
119
+ **GitHub:** [https://github.com/epicbharat](https://github.com/epicbharat)
@@ -0,0 +1,97 @@
1
+ <div align="center">
2
+ <img src="assets/logo.png" alt="KrutiExtract Logo" width="200"/>
3
+ <h1>KrutiExtract</h1>
4
+ <p><strong>A Universal Legacy Hindi PDF to Markdown Extractor</strong></p>
5
+
6
+ [![Python Version](https://img.shields.io/badge/python-3.8%2B-blue)](https://www.python.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/epicbharat)
9
+ </div>
10
+
11
+ <hr/>
12
+
13
+ Extracting legacy Hindi fonts (like **KrutiDev**, **Devlys**, or **Chanakya**) from PDF documents has traditionally been a nightmare. Standard OCR and PDF text extractors read characters based on visual coordinates. Because Hindi matras (vowel marks like `ि` or `े`) overlap with consonants, this visual sorting scrambles the text (e.g., typing `vkSj` for 'और' gets extracted as `vkjS`, breaking the conversion into the nonsense word 'आरै').
14
+
15
+ **KrutiExtract** solves this problem by bypassing visual coordinate sorting and extracting the **logical character stream** directly from the PDF.
16
+
17
+ ## ✨ Core Features
18
+
19
+ - **Perfect Character Order:** Preserves the original typist's keystrokes, completely avoiding spatial scrambling of matras.
20
+ - **Smart Auto-Detect Engine:** Automatically mathematically calculates text frequencies to detect whether the typist used **KrutiDev / Devlys** or **Chanakya**, instantly routing the text to the correct translation engine!
21
+ - **English / Hinglish Bypass Mode:** If the engine detects that the document contains modern Unicode Hindi, standard English, or Hinglish, it automatically bypasses legacy conversion entirely—perfectly preserving your modern texts!
22
+ - **Dynamic English Preservation:** Uses NLTK's English corpus to proactively detect and protect English words, numbers, acronyms, and HTML tags interspersed within mixed-font Hindi texts.
23
+ - **Collision-Free Safe-Tokens:** Markdown syntax elements (like `#` or `*`) clash with KrutiDev maps. KrutiExtract shields these structural elements using a unique `$$$INDEX$$$` safe-token system during font conversion.
24
+
25
+ ## 👁️ Advanced OCR & Image Cleaning
26
+
27
+ When the toolkit encounters text trapped inside a scanned image, it seamlessly hands it over to **Tesseract OCR** in the background.
28
+
29
+ - **Native Hindi OCR:** The toolkit hardcodes `ocr_language="hin"` into the internal pipeline. This permanently stops Tesseract from trying to hallucinate English letters onto Hindi image shapes, ensuring natively output Unicode Devanagari.
30
+ - **OpenCV Image Cleaning (`--enhance-ocr`):** Pass this flag to activate our built-in computer vision pipeline. The toolkit will automatically intercept blurry images in the PDF, upscale the resolution, apply unsharp masking, and run adaptive thresholding to perfectly reconstruct the text shapes *before* OCR scans it!
31
+
32
+ ## 🚀 Installation
33
+
34
+ Ensure you have Python 3.8+ installed.
35
+
36
+ ```bash
37
+ # Clone the repository
38
+ git clone https://github.com/epicbharat/krutiextract.git
39
+ cd krutiextract
40
+
41
+ # Create and activate a virtual environment (Recommended)
42
+ python -m venv venv
43
+ venv\Scripts\activate # On Windows
44
+ # source venv/bin/activate # On macOS/Linux
45
+
46
+ # Install dependencies
47
+ pip install -r requirements.txt
48
+
49
+ # Download the required NLTK English word corpus
50
+ python -c "import nltk; nltk.download('words')"
51
+ ```
52
+
53
+ ### Note on Tesseract (Required for OCR)
54
+ If you are parsing scanned PDFs or PDFs with embedded images, you must have [Tesseract OCR](https://github.com/tesseract-ocr/tesseract) installed on your system.
55
+ - **Windows:** Download the installer and ensure you check the **"Hindi"** language pack during installation. Add Tesseract to your PATH.
56
+ - **Linux:** `sudo apt-get install tesseract-ocr tesseract-ocr-hin`
57
+
58
+ ## 💻 CLI Usage Guide
59
+
60
+ KrutiExtract provides a powerful Command Line Interface (CLI).
61
+
62
+ ### 1. Process a Single File
63
+ ```bash
64
+ python -m src.cli --input "path/to/document.pdf" --output "path/to/output.md"
65
+ ```
66
+
67
+ ### 2. Batch Process a Directory
68
+ Recursively process an entire folder of PDFs:
69
+ ```bash
70
+ python -m src.cli --dir "path/to/pdf/folder" --out-dir "path/to/markdown/folder"
71
+ ```
72
+
73
+ ### 3. Force a Specific Font Encoding
74
+ By default, the font is set to `auto`. You can force a specific bypass or mapping:
75
+ ```bash
76
+ # Available options: krutidev, chanakya, auto, unicode, english
77
+ python -m src.cli --input "doc.pdf" --font chanakya
78
+ ```
79
+
80
+ ### 4. Enable OpenCV OCR Enhancement
81
+ Use this flag for old, blurry, or low-resolution scanned PDFs to artificially sharpen the text before extraction:
82
+ ```bash
83
+ python -m src.cli --input "blurry_scan.pdf" --enhance-ocr
84
+ ```
85
+
86
+ ## 🤝 Contributing
87
+
88
+ Contributions are welcome! If you find a PDF that breaks the extraction logic or a rare character combination we missed, please open an issue and attach the sample PDF.
89
+
90
+ ## 📄 License
91
+
92
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
93
+
94
+ ---
95
+ **Author:** Bharat Choudhary (Lecturer, Department of Secondary Education, Govt. of Rajasthan)
96
+ **Email:** epicbharat@gmail.com
97
+ **GitHub:** [https://github.com/epicbharat](https://github.com/epicbharat)
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "krutiextract"
7
+ version = "1.0.0"
8
+ authors = [
9
+ { name="Bharat Choudhary (Lecturer, Department of Secondary Education, Govt. of Rajasthan)", email="epicbharat@gmail.com" },
10
+ ]
11
+ description = "A universal toolkit for extracting legacy Hindi PDFs (KrutiDev/Devlys/Chanakya) to Markdown"
12
+ readme = "README.md"
13
+ requires-python = ">=3.8"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Topic :: Text Processing :: Linguistic",
19
+ "Natural Language :: Hindi"
20
+ ]
21
+ dependencies = [
22
+ "pymupdf",
23
+ "pymupdf4llm",
24
+ "nltk",
25
+ "opencv-python-headless",
26
+ "numpy"
27
+ ]
28
+
29
+ [project.scripts]
30
+ krutiextract = "hindi_pdf_extractor.src.cli:main"
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/epicbharat"
34
+ "Bug Tracker" = "https://github.com/epicbharat/krutiextract/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ """Source module for hindi_pdf_extractor."""
@@ -0,0 +1,69 @@
1
+ import re
2
+ from .chanakya_map import array_one, array_two
3
+
4
+ def escape_regex(s):
5
+ return re.escape(s)
6
+
7
+ def chanakya_to_unicode(text: str) -> str:
8
+ """
9
+ Converts a Chanakya encoded string into standard Devanagari Unicode.
10
+ """
11
+ if not text:
12
+ return ""
13
+
14
+ modified_substring = text
15
+
16
+ # Apply base array replacements
17
+ for i in range(len(array_one)):
18
+ pattern = re.compile(escape_regex(array_one[i]))
19
+ modified_substring = pattern.sub(array_two[i], modified_substring)
20
+
21
+ # Chanakya special rules
22
+ modified_substring = re.sub(r'Z', "üं", modified_substring)
23
+
24
+ # Handle short 'i' matra (ç)
25
+ position_of_f = modified_substring.find("ç")
26
+ while position_of_f != -1:
27
+ if position_of_f + 1 < len(modified_substring):
28
+ character_right_to_f = modified_substring[position_of_f + 1]
29
+ modified_substring = modified_substring.replace(
30
+ "ç" + character_right_to_f,
31
+ character_right_to_f + "ि"
32
+ )
33
+ # Handle half consonants after 'i' matra
34
+ pos_temp = position_of_f + 1
35
+ while pos_temp + 1 < len(modified_substring) and modified_substring[pos_temp + 1] == "्":
36
+ if pos_temp + 2 < len(modified_substring):
37
+ string_to_be_replaced = modified_substring[pos_temp + 1] + modified_substring[pos_temp + 2]
38
+ modified_substring = modified_substring.replace("ि" + string_to_be_replaced, string_to_be_replaced + "ि")
39
+ pos_temp += 2
40
+ else:
41
+ break
42
+ position_of_f = modified_substring.find("ç", position_of_f + 1)
43
+
44
+ # Reorder 'R' matras (ü -> र्)
45
+ set_of_matras = "ा ि ी ु ू ृ े ै ो ौ ं ः ँ ॅ"
46
+ position_of_Z = modified_substring.find("ü")
47
+
48
+ while position_of_Z > 0:
49
+ probable_position_of_half_r = position_of_Z - 1
50
+ character_at_probable_position_of_half_r = modified_substring[probable_position_of_half_r]
51
+
52
+ while character_at_probable_position_of_half_r in set_of_matras and probable_position_of_half_r >= 0:
53
+ probable_position_of_half_r -= 1
54
+ if probable_position_of_half_r >= 0:
55
+ character_at_probable_position_of_half_r = modified_substring[probable_position_of_half_r]
56
+
57
+ if probable_position_of_half_r >= 0:
58
+ substring_to_be_replaced = modified_substring[probable_position_of_half_r:position_of_Z + 1]
59
+ replace_with = "र्" + modified_substring[probable_position_of_half_r:position_of_Z]
60
+ modified_substring = modified_substring.replace(substring_to_be_replaced, replace_with)
61
+
62
+ position_of_Z = modified_substring.find("ü", position_of_Z + 1)
63
+
64
+ # Final cleanup
65
+ modified_substring = modified_substring.replace("ंे", "ें")
66
+ modified_substring = modified_substring.replace("ंो", "ों")
67
+ modified_substring = modified_substring.replace("ाे", "ो")
68
+
69
+ return modified_substring