commit e22334952d642c3a3ecc42011f54063630f488e3
Author: kirbylife <kirbylife@protonmail.com>
Date:   Sat May 11 01:19:08 2024 -0600

    First commit

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..09df62f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+A simple MD to HTML converter
+
+## Compilation
+
+1. `git clone https://git.kirbylife.dev/kirbylife/nim-md-to-html`
+1. `cd nim-md-to-html`
+1. `nimble build -d:release`
+
+## Usage
+
+1. `nim-md-to-html <path/to/file.md> </path/to/theme.css> > index.html`
+
+The theme must be a classless CSS file.  
+I personally recommend [water.css](https://watercss.kognise.dev/), but on the internet there is a good variety, choose the one you like the most.
+
+
+## License
+
+This project is licensed under the LGPL 3.0 license.
\ No newline at end of file
diff --git a/md_to_html_embed.nimble b/md_to_html_embed.nimble
new file mode 100644
index 0000000..7688132
--- /dev/null
+++ b/md_to_html_embed.nimble
@@ -0,0 +1,16 @@
+# Package
+
+version       = "0.1.0"
+author        = "kirbylife"
+description   = "A simple MD to HTML converter"
+license       = "LGPL-3.0-or-later"
+srcDir        = "src"
+bin           = @["md_to_html_embed"]
+
+
+# Dependencies
+
+requires "nim >= 2.0"
+requires "markdown == 0.8.7"
+requires "glob == 0.11.3"
+requires "regex == 0.25.0"
diff --git a/src/md_to_html_embed.nim b/src/md_to_html_embed.nim
new file mode 100644
index 0000000..2771892
--- /dev/null
+++ b/src/md_to_html_embed.nim
@@ -0,0 +1,85 @@
+import markdown
+import glob
+import regex
+import std/htmlparser
+import std/xmltree
+import std/strtabs
+import std/strutils
+import std/os
+import std/paths
+import std/sequtils
+import std/streams
+import std/base64
+
+const MAXOUTERLIMIT = 2
+
+proc applyTheme(html: XmlNode, theme: string) =
+  let charset_att = {"charset": "utf-8"}.toXmlAttributes()
+  let charset =  newXmlTree("meta", [], charset_att)
+
+  let theme_att = {"style": "text/css"}.toXmlAttributes()
+  let theme_content = newText(theme)
+  let style = newXmlTree("style", [theme_content], theme_att)
+
+  let head = newXmlTree("head", [charset, style])
+
+  html.insert(head, 0)
+
+proc bytesToBase64(bytes: seq[byte]): string =
+  return " data:image/jpeg;charset=utf8;base64," & bytes.encode()
+
+proc pathToBytes(path: string): seq[byte] =
+  const block_size = 4096
+
+  var
+    buffer: array[block_size, byte]
+    bytes: seq[byte]
+    total_bytes_readed = 0
+
+  let strm = openFileStream(path, fmRead)
+
+  while true:
+    let bytes_readed = strm.readData(addr(buffer), block_size)
+    if bytes_readed == 0:
+      break
+    bytes.add(buffer[0..<bytes_readed])
+
+  strm.close()
+
+  return bytes
+
+proc embedImages(html: XmlNode, root: string) =
+  for node in html.findAll("img"):
+    # echo node
+    if node.attrs.hasKey("src"):
+      var src = node.attrs["src"]
+      if src.isEmptyOrWhitespace():
+        continue
+      if not src.startsWith("http"):
+        let search_param = root / "../".repeat(MAXOUTERLIMIT) / "**" /  src
+        let possible_attempts = walkGlob(search_param).toSeq()
+        if possible_attempts.len() > 0:
+          let img_path = possible_attempts[0]
+          src = img_path.pathToBytes().bytesToBase64()
+          node.attrs["src"] = src
+
+        # let img_bytes = pathToBytes(src)
+
+when isMainModule and declared(commandLineParams):
+  let
+    params = commandLineParams()
+    md_src = absolutePath(params[0])
+    md_root = splitFile(md_src).dir
+    theme_src = params[1]
+
+  let raw_md = readFile(md_src).replace(re2"!\[\[(.+)\]\]", "<img src=\"$1\">")
+  let raw_html = markdown(raw_md, config=initGfmConfig())
+  let parsed_html = parseHtml(raw_html)
+
+  let raw_theme = readFile(theme_src)
+
+  embedImages(parsed_html, md_root)
+  applyTheme(parsed_html, raw_theme)
+
+  echo parsed_html
+