Repository: mkdocs/mkdocs

Issue:
Embed images
According to the docs 

```
mkdocs.yml
docs/
    CNAME
    index.md
    subpage.md
    img/
        screenshot.png
```

```
index.md
![Screenshot](img/screenshot.png)
```

This is all good if you adding images to index.md

Now let's consider subpage: 

```
subpage.md
![Screenshot](img/screenshot.png)
```

This image isn't found as server wants it to be in subpage/img/screenshot.png ?? 
So this forces invalid markup which doesn't work with other MD engines! 

```
subpage.md
![Screenshot](../img/screenshot.png)
```



Discussion:
:+1:

The problem, is that subpage.md moves to subpage/index.html and thus the relative location of the img is incorrect. To fix this I think we need to infer an abolute location (by resolving the relative one to the .md file) and then use for image links.

However, AFAICT, this will involve processing and re-writing the HTML which would get messy.

Any better ideas?

I'm confused. As far as I'm aware we do infer the correct relative location, which when translated into a URL will differ depending on if it was a link from `subpage.md` or `index.md`.

> To fix this I think we need to infer an abolute location

I can't see why we'd need to be moving away from the current relative URLs, although if they're currently incorrectly generated for non-index pages then that needs fixing of course.

How should an image be added on subpage.md? Given the structure above? Maybe we just need to document this better, I don't fully understand but requiring people to put "../" seems wrong when that extra level isn't there in the source files.

Yup indeed - the source should be marked up as `![Screenshot](img/screenshot.png)` in both cases, but the translation to HTML should render different links in each case, including the required `..` in one case but not in the other. As far as I was concerned we're handling both cases correctly when we translate them into relative URLs, but haven't checked lately.

Right, so I tested this and confirmed the issue. I'll investigate the fix. I'm not sure which bit of the code is responsible for this yet.


Resolving patch:
diff --git a/mkdocs/build.py b/mkdocs/build.py
--- a/mkdocs/build.py
+++ b/mkdocs/build.py
@@ -10,18 +10,21 @@
 
 
 class PathToURL(object):
-    def __init__(self, nav=None):
+    def __init__(self, template, nav=None):
+        self.template = template
         self.nav = nav
 
     def __call__(self, match):
         url = match.groups()[0]
         scheme, netloc, path, query, query, fragment = urlparse(url)
 
-        if (scheme or netloc or not utils.is_markdown_file(path)):
+        if scheme or netloc:
             # Ignore URLs unless they are a relative link to a markdown file.
-            return 'a href="%s"' % url
+            return self.template % url
 
-        if self.nav:
+        if self.nav and not utils.is_markdown_file(path):
+            path = utils.create_media_urls(self.nav, [path])[0]
+        elif self.nav:
             # If the site navigation has been provided, then validate
             # the internal hyperlink, making sure the target actually exists.
             target_file = self.nav.file_context.make_absolute(path)
@@ -39,7 +42,7 @@ def __call__(self, match):
 
         # Convert the .md hyperlink to a relative hyperlink to the HTML page.
         url = urlunparse((scheme, netloc, path, query, query, fragment))
-        return 'a href="%s"' % url
+        return self.template % url
 
 
 def convert_markdown(markdown_source, extensions=()):
@@ -72,8 +75,15 @@ def convert_markdown(markdown_source, extensions=()):
 
 
 def post_process_html(html_content, nav=None):
-    html_content = re.sub(r'a href="([^"]*)"', PathToURL(nav), html_content)
-    html_content = re.sub('<pre>', '<pre class="prettyprint well">', html_content)
+
+    anchor_sub = PathToURL('a href="%s"', nav)
+    html_content = re.sub(r'a href="([^"]*)"', anchor_sub, html_content)
+
+    img_sub = PathToURL('src="%s"', nav)
+    html_content = re.sub(r'src="([^"]*)"', img_sub, html_content)
+
+    html_content = html_content.replace('<pre>', '<pre class="prettyprint well">')
+
     return html_content
 
 
diff --git a/mkdocs/compat.py b/mkdocs/compat.py
--- a/mkdocs/compat.py
+++ b/mkdocs/compat.py
@@ -14,6 +14,9 @@
     import SocketServer
     socketserver = SocketServer
 
+    import itertools
+    zip = itertools.izip
+
     text_type = unicode
     binary_type = str
     string_types = (str, unicode)
@@ -28,6 +31,8 @@
     import socketserver
     socketserver = socketserver
 
+    zip = zip
+
     text_type = str
     binary_type = bytes
     string_types = (str,)
diff --git a/mkdocs/nav.py b/mkdocs/nav.py
--- a/mkdocs/nav.py
+++ b/mkdocs/nav.py
@@ -98,7 +98,10 @@ def make_relative(self, url):
                 # Workaround for static assets
                 return '.'
             return url.lstrip('/')
-        return posixpath.relpath(url, start=self.base_path) + suffix
+        relative_path = posixpath.relpath(url, start=self.base_path) + suffix
+
+        # Under Python 2.6, relative_path adds an extra '/' at the end.
+        return relative_path.rstrip('/')
 
 
 class FileContext(object):


Test patch:
diff --git a/mkdocs/test.py b/mkdocs/test.py
--- a/mkdocs/test.py
+++ b/mkdocs/test.py
@@ -3,7 +3,7 @@
 
 
 from mkdocs import build, nav, toc, utils, config
-from mkdocs.compat import PY2
+from mkdocs.compat import PY2, zip
 import markdown
 import os
 import shutil
@@ -431,6 +431,26 @@ def test_convert_internal_link_with_anchor(self):
         html = build.post_process_html(html)
         self.assertEqual(html.strip(), expected.strip())
 
+    def test_convert_internal_media(self):
+        pages = [
+            ('index.md',),
+            ('internal.md',),
+            ('sub/internal.md')
+        ]
+
+        site_navigation = nav.SiteNavigation(pages)
+
+        expected_results = (
+            '<p><img alt="The initial MkDocs layout" src="./img/initial-layout.png" /></p>',
+            '<p><img alt="The initial MkDocs layout" src="../img/initial-layout.png" /></p>',
+            '<p><img alt="The initial MkDocs layout" src="../../img/initial-layout.png" /></p>',
+        )
+
+        for (page, expected) in zip(site_navigation.walk_pages(), expected_results):
+            html = '<p><img alt="The initial MkDocs layout" src="img/initial-layout.png" /></p>'
+            html = build.post_process_html(html, site_navigation)
+            self.assertEqual(html, expected)
+
     def test_ignore_external_link(self):
         md_text = 'An [external link](http://example.com/external.md).'
         expected = '<p>An <a href="http://example.com/external.md">external link</a>.</p>'