strx-md2pdf 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,35 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ env/
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+
24
+ # Virtualenv
25
+ venv/
26
+ ENV/
27
+
28
+ # OS
29
+ .DS_Store
30
+ .DS_Store?
31
+ ._*
32
+ .Spotlight-V100
33
+ .Trashes
34
+ ehthumbs.db
35
+ Thumbs.db
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Straconx
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,91 @@
1
+ Metadata-Version: 2.4
2
+ Name: strx-md2pdf
3
+ Version: 1.0.0
4
+ Summary: Conversor de Markdown a PDF con estilos profesionales y soporte para checkboxes
5
+ Project-URL: Homepage, https://github.com/straconx/strx-md2pdf
6
+ Project-URL: Bug-Tracker, https://github.com/straconx/strx-md2pdf/issues
7
+ Author-email: Straconx <info@straconx.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: converter,markdown,pdf,straconx,weasyprint
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
16
+ Requires-Python: >=3.8
17
+ Requires-Dist: markdown>=3.0
18
+ Requires-Dist: pygments>=2.0
19
+ Requires-Dist: weasyprint>=52.0
20
+ Description-Content-Type: text/markdown
21
+
22
+ # STRX Markdown to PDF Converter
23
+
24
+ Herramienta para convertir archivos Markdown a PDF con estilos profesionales.
25
+
26
+ ## Características
27
+
28
+ - ✅ Conversión de Markdown a PDF con formato profesional.
29
+ - ✅ Soporte para checkboxes `[ ]` y `[x]`.
30
+ - ✅ Soporte para tablas, listas, código y más.
31
+ - ✅ Estilos CSS personalizados y profesionales.
32
+ - ✅ Numeración automática de páginas y diseño optimizado para A4.
33
+ - ✅ Resaltado de sintaxis para bloques de código.
34
+ - ✅ Tabla de contenidos automática.
35
+
36
+ ## Instalación
37
+
38
+ Puedes instalar esta herramienta directamente desde el código fuente o como un paquete de Python.
39
+
40
+ ### Desde el código fuente (para desarrollo)
41
+
42
+ ```bash
43
+ cd /odoo20/strx_tools/strx_md2pdf
44
+ pip install -e .
45
+ ```
46
+
47
+ ### Instalación normal
48
+
49
+ ```bash
50
+ pip install /odoo20/strx_tools/strx_md2pdf
51
+ ```
52
+
53
+ ## Uso
54
+
55
+ Una vez instalado, el comando `strx_md2pdf` estará disponible en tu terminal.
56
+
57
+ ### Uso básico
58
+
59
+ ```bash
60
+ # Genera archivo.pdf en el mismo directorio
61
+ strx_md2pdf archivo.md
62
+ ```
63
+
64
+ ### Especificar archivo de salida
65
+
66
+ ```bash
67
+ strx_md2pdf archivo.md /ruta/al/destino/salida.pdf
68
+ ```
69
+
70
+ ### Usar como módulo de Python
71
+
72
+ ```bash
73
+ python3 -m strx_md2pdf archivo.md
74
+ ```
75
+
76
+ ## Requisitos del sistema
77
+
78
+ Para que `weasyprint` funcione correctamente, es posible que necesites instalar algunas dependencias del sistema dependiendo de tu OS.
79
+
80
+ En Ubuntu/Debian:
81
+ ```bash
82
+ sudo apt-get install python3-pip python3-cffi python3-brotli libpango-1.0-0 libharfbuzz0b libpangoft2-1.0-0
83
+ ```
84
+
85
+ ## Autor
86
+
87
+ Straconx - Equipo de Initium 20
88
+
89
+ ## Licencia
90
+
91
+ MIT
@@ -0,0 +1,70 @@
1
+ # STRX Markdown to PDF Converter
2
+
3
+ Herramienta para convertir archivos Markdown a PDF con estilos profesionales.
4
+
5
+ ## Características
6
+
7
+ - ✅ Conversión de Markdown a PDF con formato profesional.
8
+ - ✅ Soporte para checkboxes `[ ]` y `[x]`.
9
+ - ✅ Soporte para tablas, listas, código y más.
10
+ - ✅ Estilos CSS personalizados y profesionales.
11
+ - ✅ Numeración automática de páginas y diseño optimizado para A4.
12
+ - ✅ Resaltado de sintaxis para bloques de código.
13
+ - ✅ Tabla de contenidos automática.
14
+
15
+ ## Instalación
16
+
17
+ Puedes instalar esta herramienta directamente desde el código fuente o como un paquete de Python.
18
+
19
+ ### Desde el código fuente (para desarrollo)
20
+
21
+ ```bash
22
+ cd /odoo20/strx_tools/strx_md2pdf
23
+ pip install -e .
24
+ ```
25
+
26
+ ### Instalación normal
27
+
28
+ ```bash
29
+ pip install /odoo20/strx_tools/strx_md2pdf
30
+ ```
31
+
32
+ ## Uso
33
+
34
+ Una vez instalado, el comando `strx_md2pdf` estará disponible en tu terminal.
35
+
36
+ ### Uso básico
37
+
38
+ ```bash
39
+ # Genera archivo.pdf en el mismo directorio
40
+ strx_md2pdf archivo.md
41
+ ```
42
+
43
+ ### Especificar archivo de salida
44
+
45
+ ```bash
46
+ strx_md2pdf archivo.md /ruta/al/destino/salida.pdf
47
+ ```
48
+
49
+ ### Usar como módulo de Python
50
+
51
+ ```bash
52
+ python3 -m strx_md2pdf archivo.md
53
+ ```
54
+
55
+ ## Requisitos del sistema
56
+
57
+ Para que `weasyprint` funcione correctamente, es posible que necesites instalar algunas dependencias del sistema dependiendo de tu OS.
58
+
59
+ En Ubuntu/Debian:
60
+ ```bash
61
+ sudo apt-get install python3-pip python3-cffi python3-brotli libpango-1.0-0 libharfbuzz0b libpangoft2-1.0-0
62
+ ```
63
+
64
+ ## Autor
65
+
66
+ Straconx - Equipo de Initium 20
67
+
68
+ ## Licencia
69
+
70
+ MIT
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "strx-md2pdf"
7
+ version = "1.0.0"
8
+ description = "Conversor de Markdown a PDF con estilos profesionales y soporte para checkboxes"
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "Straconx", email = "info@straconx.com" }
12
+ ]
13
+ license = { text = "MIT" }
14
+ keywords = ["markdown", "pdf", "converter", "weasyprint", "straconx"]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent",
19
+ "Topic :: Text Processing :: Markup :: Markdown",
20
+ "Intended Audience :: Developers",
21
+ ]
22
+ dependencies = [
23
+ "markdown>=3.0",
24
+ "weasyprint>=52.0",
25
+ "Pygments>=2.0",
26
+ ]
27
+ requires-python = ">=3.8"
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/straconx/strx-md2pdf"
31
+ Bug-Tracker = "https://github.com/straconx/strx-md2pdf/issues"
32
+
33
+ [project.scripts]
34
+ strx_md2pdf = "strx_md2pdf.main:main"
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/strx_md2pdf"]
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ STRX Markdown to PDF Converter
5
+ ===============================
6
+
7
+ Script para convertir archivos Markdown a PDF usando WeasyPrint.
8
+ Soporta checkboxes de Markdown y genera un PDF con estilos profesionales.
9
+
10
+ Uso:
11
+ strx_md2pdf <archivo.md> [salida.pdf]
12
+ python3 -m strx_md2pdf <archivo.md> [salida.pdf]
13
+ """
14
+
15
+ import argparse
16
+ import sys
17
+ import re
18
+ from pathlib import Path
19
+ import markdown
20
+ try:
21
+ from weasyprint import HTML, CSS
22
+ except ImportError:
23
+ print("❌ Error: WeasyPrint no está instalado. Instálalo con 'pip install weasyprint'")
24
+ sys.exit(1)
25
+
26
+
27
+ def markdown_to_html(md_content):
28
+ """
29
+ Convierte contenido Markdown a HTML con extensiones.
30
+ """
31
+ md = markdown.Markdown(extensions=[
32
+ 'extra', # Tablas, atributos, etc.
33
+ 'nl2br', # Convierte saltos de línea en <br>
34
+ 'sane_lists', # Mejora el manejo de listas
35
+ 'codehilite', # Resaltado de código
36
+ 'toc', # Tabla de contenidos
37
+ ])
38
+ return md.convert(md_content)
39
+
40
+
41
+ def process_checkboxes(html_content):
42
+ """
43
+ Procesa checkboxes de Markdown [ ] y [x] para mostrarlos en el PDF.
44
+ """
45
+ # Reemplazar [ ] con ☐ seguido de espacio
46
+ html_content = html_content.replace('[ ]', '☐&nbsp;')
47
+ # Reemplazar [x] o [X] con ☑ seguido de espacio
48
+ html_content = html_content.replace('[x]', '☑&nbsp;')
49
+ html_content = html_content.replace('[X]', '☑&nbsp;')
50
+
51
+ # Agregar clase task-item a los <li> que contienen checkboxes
52
+ html_content = re.sub(
53
+ r'<li>([☐☑]&nbsp;)',
54
+ r'<li class="task-item">\1',
55
+ html_content
56
+ )
57
+
58
+ # También manejar casos donde hay un <p> dentro del <li>
59
+ html_content = re.sub(
60
+ r'<li><p>([☐☑]&nbsp;)',
61
+ r'<li class="task-item"><p>\1',
62
+ html_content
63
+ )
64
+
65
+ return html_content
66
+
67
+
68
+ def create_styled_html(title, body_html):
69
+ """
70
+ Crea un documento HTML completo con estilos CSS profesionales.
71
+ """
72
+ return f"""
73
+ <!DOCTYPE html>
74
+ <html lang="es">
75
+ <head>
76
+ <meta charset="UTF-8">
77
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
78
+ <title>{title}</title>
79
+ <style>
80
+ @page {{
81
+ size: A4;
82
+ margin: 2cm;
83
+ @bottom-right {{
84
+ content: "Página " counter(page) " de " counter(pages);
85
+ font-size: 10px;
86
+ color: #666;
87
+ }}
88
+ }}
89
+
90
+ body {{
91
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
92
+ line-height: 1.6;
93
+ color: #333;
94
+ max-width: 100%;
95
+ font-size: 11pt;
96
+ }}
97
+
98
+ h1 {{
99
+ color: #2c3e50;
100
+ border-bottom: 3px solid #3498db;
101
+ padding-bottom: 10px;
102
+ margin-top: 30px;
103
+ font-size: 28pt;
104
+ page-break-after: avoid;
105
+ }}
106
+
107
+ h2 {{
108
+ color: #34495e;
109
+ border-bottom: 2px solid #95a5a6;
110
+ padding-bottom: 8px;
111
+ margin-top: 25px;
112
+ font-size: 20pt;
113
+ page-break-after: avoid;
114
+ }}
115
+
116
+ h3 {{
117
+ color: #555;
118
+ margin-top: 20px;
119
+ font-size: 16pt;
120
+ page-break-after: avoid;
121
+ }}
122
+
123
+ h4, h5, h6 {{
124
+ color: #666;
125
+ margin-top: 15px;
126
+ page-break-after: avoid;
127
+ }}
128
+
129
+ ul, ol {{
130
+ margin: 10px 0;
131
+ padding-left: 30px;
132
+ }}
133
+
134
+ li {{
135
+ margin: 5px 0;
136
+ padding-left: 8px;
137
+ page-break-inside: avoid;
138
+ }}
139
+
140
+ /* Remover viñetas solo de items de tareas (checkboxes) */
141
+ li.task-item {{
142
+ list-style-type: none;
143
+ margin-left: -25px;
144
+ padding-left: 0;
145
+ text-indent: 0;
146
+ }}
147
+
148
+ code {{
149
+ background-color: #f4f4f4;
150
+ border: 1px solid #ddd;
151
+ border-radius: 3px;
152
+ padding: 2px 6px;
153
+ font-family: 'Courier New', Courier, monospace;
154
+ font-size: 10pt;
155
+ }}
156
+
157
+ pre {{
158
+ background-color: #f8f8f8;
159
+ border: 1px solid #ddd;
160
+ border-radius: 5px;
161
+ padding: 15px;
162
+ overflow-x: auto;
163
+ page-break-inside: avoid;
164
+ }}
165
+
166
+ pre code {{
167
+ background: none;
168
+ border: none;
169
+ padding: 0;
170
+ }}
171
+
172
+ blockquote {{
173
+ border-left: 4px solid #3498db;
174
+ margin: 15px 0;
175
+ padding: 10px 20px;
176
+ background-color: #f9f9f9;
177
+ font-style: italic;
178
+ }}
179
+
180
+ table {{
181
+ border-collapse: collapse;
182
+ width: 100%;
183
+ margin: 20px 0;
184
+ page-break-inside: avoid;
185
+ }}
186
+
187
+ th, td {{
188
+ border: 1px solid #ddd;
189
+ padding: 12px;
190
+ text-align: left;
191
+ }}
192
+
193
+ th {{
194
+ background-color: #3498db;
195
+ color: white;
196
+ font-weight: bold;
197
+ }}
198
+
199
+ tr:nth-child(even) {{
200
+ background-color: #f2f2f2;
201
+ }}
202
+
203
+ a {{
204
+ color: #3498db;
205
+ text-decoration: none;
206
+ }}
207
+
208
+ a:hover {{
209
+ text-decoration: underline;
210
+ }}
211
+
212
+ .checkbox {{
213
+ font-size: 14pt;
214
+ margin-right: 5px;
215
+ }}
216
+
217
+ hr {{
218
+ border: none;
219
+ border-top: 2px solid #ddd;
220
+ margin: 30px 0;
221
+ }}
222
+ </style>
223
+ </head>
224
+ <body>
225
+ {body_html}
226
+ </body>
227
+ </html>
228
+ """
229
+
230
+
231
+ def convert_md_to_pdf(input_file, output_file=None):
232
+ """
233
+ Convierte un archivo Markdown a PDF.
234
+ """
235
+ input_path = Path(input_file)
236
+
237
+ if not input_path.exists():
238
+ raise FileNotFoundError(f"El archivo '{input_file}' no existe.")
239
+
240
+ if not input_path.is_file():
241
+ raise ValueError(f"'{input_file}' no es un archivo válido.")
242
+
243
+ # Determinar el archivo de salida
244
+ if output_file is None:
245
+ output_path = input_path.with_suffix('.pdf')
246
+ else:
247
+ output_path = Path(output_file)
248
+ # Crear directorios si no existen
249
+ output_path.parent.mkdir(parents=True, exist_ok=True)
250
+
251
+ # Leer el contenido del archivo Markdown
252
+ print(f"📖 Leyendo archivo: {input_path}")
253
+ with open(input_path, 'r', encoding='utf-8') as f:
254
+ md_content = f.read()
255
+
256
+ # Convertir Markdown a HTML
257
+ print("🔄 Convirtiendo Markdown a HTML...")
258
+ html_body = markdown_to_html(md_content)
259
+
260
+ # Procesar checkboxes
261
+ html_body = process_checkboxes(html_body)
262
+
263
+ # Crear HTML completo con estilos
264
+ title = input_path.stem
265
+ full_html = create_styled_html(title, html_body)
266
+
267
+ # Convertir HTML a PDF
268
+ print(f"📄 Generando PDF: {output_path}")
269
+ HTML(string=full_html).write_pdf(output_path)
270
+
271
+ print(f"✅ PDF generado exitosamente: {output_path}")
272
+ return str(output_path)
273
+
274
+
275
+ def main():
276
+ """Función principal del script."""
277
+ parser = argparse.ArgumentParser(
278
+ description='Convierte archivos Markdown a PDF con estilos profesionales.',
279
+ formatter_class=argparse.RawDescriptionHelpFormatter,
280
+ epilog="""
281
+ Ejemplos:
282
+ strx_md2pdf README.md
283
+ strx_md2pdf docs/manual.md output/manual.pdf
284
+ """
285
+ )
286
+
287
+ parser.add_argument(
288
+ 'input',
289
+ help='Archivo Markdown de entrada (.md)'
290
+ )
291
+
292
+ parser.add_argument(
293
+ 'output',
294
+ nargs='?',
295
+ default=None,
296
+ help='Archivo PDF de salida (opcional, por defecto usa el mismo nombre con .pdf)'
297
+ )
298
+
299
+ parser.add_argument(
300
+ '-v', '--version',
301
+ action='version',
302
+ version='strx_md2pdf 1.0.0'
303
+ )
304
+
305
+ args = parser.parse_args()
306
+
307
+ try:
308
+ convert_md_to_pdf(args.input, args.output)
309
+ return 0
310
+ except Exception as e:
311
+ print(f"❌ Error: {e}", file=sys.stderr)
312
+ return 1
313
+
314
+
315
+ if __name__ == '__main__':
316
+ sys.exit(main())