mirror of https://github.com/MISP/misp-modules
chg: [expansion:convert_markdown_to_pdf] Better support of margins and added installation notes
- Add to introduce hacky code as wkhtmltopdf could not correctly parse margins and other options such as --disable-smart-shrinking when passed by pandocpull/702/head
parent
e17aad3aeb
commit
e8537592d7
|
@ -3,38 +3,147 @@
|
|||
import json
|
||||
import base64
|
||||
import pandoc
|
||||
import random
|
||||
import string
|
||||
import subprocess
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
installationNotes = '''
|
||||
1. Install pandoc for your distribution
|
||||
2. Install wkhtmltopdf
|
||||
- Ensure You have install the version with patched qt
|
||||
- Ensure it supports margin options
|
||||
- You can check the above by inspecting the extended help `wkhtmltopdf --extended-help`
|
||||
3. Install mermaid
|
||||
- `npm install --global @mermaid-js/mermaid-cli`
|
||||
4. Install the pandoc-mermaid-filter from https://github.com/DavidCruciani/pandoc-mermaid-filter
|
||||
- Easiest is to install the following:
|
||||
```bash
|
||||
pip3 install git+https://github.com/DavidCruciani/pandoc-mermaid-filter
|
||||
```
|
||||
'''
|
||||
|
||||
misperrors = {'error': 'Error'}
|
||||
mispattributes = {'input': ['text'], 'output': ['text']}
|
||||
moduleinfo = {
|
||||
'version': '0.2',
|
||||
'version': '0.3',
|
||||
'author': 'Sami Mokaddem',
|
||||
'description': 'Render the markdown (under GFM) into PDF. Requires pandoc (https://pandoc.org/) and wkhtmltopdf (https://wkhtmltopdf.org/).',
|
||||
'description': 'Render the markdown (under GFM) into PDF. Requires pandoc (https://pandoc.org/), wkhtmltopdf (https://wkhtmltopdf.org/) and mermaid dependencies.',
|
||||
'module-type': ['expansion'],
|
||||
'name': 'Markdown to PDF converter',
|
||||
'logo': '',
|
||||
'requirements': ['pandoc'],
|
||||
'features': '',
|
||||
'references': [],
|
||||
'references': [installationNotes],
|
||||
'input': '',
|
||||
'output': '',
|
||||
}
|
||||
|
||||
moduleconfig = [
|
||||
'margin',
|
||||
]
|
||||
|
||||
def randomFilename(length=10):
|
||||
characters = string.ascii_lowercase + string.digits # Lowercase letters and digits
|
||||
return ''.join(random.choices(characters, k=length))
|
||||
|
||||
def convert(markdown, margin='3'):
|
||||
doc = pandoc.read(markdown, format='gfm')
|
||||
options = [
|
||||
'--pdf-engine=wkhtmltopdf',
|
||||
f'-V margin-left={margin}',
|
||||
f'-V margin-right={margin}',
|
||||
f'-V margin-top={margin}',
|
||||
f'-V margin-bottom={margin}',
|
||||
|
||||
elt = doc
|
||||
|
||||
# wrap/unwrap Inline or MetaInlines into [Inline]
|
||||
if isinstance(elt, pandoc.types.Inline):
|
||||
inline = elt
|
||||
elt = [inline]
|
||||
elif isinstance(elt, pandoc.types.MetaInlines):
|
||||
meta_inlines = elt
|
||||
elt = meta_inlines[0]
|
||||
|
||||
# wrap [Inline] into a Plain element
|
||||
if isinstance(elt, list) and all(isinstance(elt_, pandoc.types.Inline) for elt_ in elt):
|
||||
inlines = elt
|
||||
elt = pandoc.types.Plain(inlines)
|
||||
|
||||
# wrap/unwrap Block or MetaBlocks into [Block]
|
||||
if isinstance(elt, pandoc.types.Block):
|
||||
block = elt
|
||||
elt = [block]
|
||||
elif isinstance(elt, pandoc.types.MetaBlocks):
|
||||
meta_blocks = elt
|
||||
elt = meta_blocks[0]
|
||||
|
||||
# wrap [Block] into a Pandoc element
|
||||
if isinstance(elt, list) and all(isinstance(elt_, pandoc.types.Block) for elt_ in elt):
|
||||
blocks = elt
|
||||
elt = pandoc.types.Pandoc(pandoc.types.Meta({}), blocks)
|
||||
|
||||
if not isinstance(elt, pandoc.types.Pandoc):
|
||||
raise TypeError(f"{elt!r} is not a Pandoc, Block or Inline instance.")
|
||||
|
||||
doc = elt
|
||||
|
||||
# options = [
|
||||
# '--pdf-engine=wkhtmltopdf',
|
||||
# f'-V margin-left={margin}',
|
||||
# f'-V margin-right={margin}',
|
||||
# f'-V margin-top={margin}',
|
||||
# f'-V margin-bottom={margin}',
|
||||
# '--pdf-engine-opt="--disable-smart-shrinking"',
|
||||
# ]
|
||||
randomFn = randomFilename()
|
||||
command = [
|
||||
"/usr/bin/pandoc",
|
||||
"-t", "pdf",
|
||||
"-o", f"/tmp/{randomFn}/output",
|
||||
"--pdf-engine=wkhtmltopdf",
|
||||
"-V", f"margin-left={margin}",
|
||||
"-V", f"margin-right={margin}",
|
||||
"-V", f"margin-top={margin}",
|
||||
"-V", f"margin-bottom={margin}",
|
||||
"--pdf-engine-opt=--disable-smart-shrinking",
|
||||
"--filter=pandoc-mermaid",
|
||||
"-f", "json",
|
||||
f"/tmp/{randomFn}/input.js"
|
||||
]
|
||||
converted = pandoc.write(doc, format='pdf', options=options)
|
||||
# try:
|
||||
# # For some reasons, options are not passed correctly or not parsed correctly by wkhtmltopdf..
|
||||
# # converted = pandoc.write(doc, format='pdf', options=options)
|
||||
# except Exception as e:
|
||||
# print(e)
|
||||
|
||||
os.makedirs(f'/tmp/{randomFn}', exist_ok=True)
|
||||
# Write parsed file structure to be fed to the converter
|
||||
with open(f'/tmp/{randomFn}/input.js', 'bw') as f:
|
||||
configuration = pandoc.configure(read=True)
|
||||
if pandoc.utils.version_key(configuration["pandoc_types_version"]) < [1, 17]:
|
||||
json_ = pandoc.write_json_v1(doc)
|
||||
else:
|
||||
json_ = pandoc.write_json_v2(doc)
|
||||
json_str = json.dumps(json_)
|
||||
f.write(json_str.encode("utf-8"))
|
||||
|
||||
# Do conversion by manually invoking pandoc
|
||||
try:
|
||||
subprocess.run(command, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Command failed with error: {e}")
|
||||
|
||||
# Read output and returns it
|
||||
with open(f'/tmp/{randomFn}/output', 'br') as f:
|
||||
converted = f.read()
|
||||
|
||||
# Clean up generated files
|
||||
folderPath = f'/tmp/{randomFn}'
|
||||
try:
|
||||
shutil.rmtree(folderPath)
|
||||
print(f"Folder '{folderPath}' deleted successfully.")
|
||||
except FileNotFoundError:
|
||||
print(f"Folder '{folderPath}' does not exist.")
|
||||
except Exception as e:
|
||||
print(f"Error deleting folder '{folderPath}': {e}")
|
||||
|
||||
return base64.b64encode(converted).decode()
|
||||
|
||||
def handler(q=False):
|
||||
|
|
Loading…
Reference in New Issue