Images in HTML not portable

1,516 views
Skip to first unread message

Alex Perrone

unread,
May 10, 2014, 2:26:03 PM5/10/14
to kn...@googlegroups.com
If I embed a local image in a markdown file (i.e. using a path to say a PNG file saved previously) and output to HTML, this is not portable. The HTML does not actually contain the image unlike say when the markdown is converted to a PDF from pandoc. The HTML just points to the file location, apparently. Is there any way to get the HTML to *actually* embed the image so that it's portable (and not pointed to via a URL)? 

(I realize this may be a more markdown question but it can up while using knitr.) 

Thanks,
Alex

Yihui Xie

unread,
May 10, 2014, 3:31:03 PM5/10/14
to Alex Perrone, knitr
There are many ways to convert markdown to HTML and each way has a
variety of different options, so please tell us clearly what you did,
otherwise we can provide nothing helpful except saying base64 encoding
is pretty much the only direction to go.

Regards,
Yihui
--
Yihui Xie <xiey...@gmail.com>
Web: http://yihui.name

Alex Perrone

unread,
May 10, 2014, 3:54:53 PM5/10/14
to kn...@googlegroups.com
Here is a minimal example. Given the markdown document `example.md`: 

# Image
![](/path/to/my_image.png)

I convert to html using `pandoc -s example.md -o example.html`. 

But If rename or move my_image.png (or send the output HTML file to someone else), the image does not appear. Question: how do I embed the image into the HTML so that it is portable and impervious to changes in original image? 

Henrik Bengtsson

unread,
May 10, 2014, 4:03:11 PM5/10/14
to Alex Perrone, kn...@googlegroups.com
pandoc --self-contained ... It's in the Pandoc User Guide
[http://johnmacfarlane.net/pandoc/README.html].

/Henrik
> --
> You received this message because you are subscribed to the Google Groups
> "knitr" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to knitr+un...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Alex Perrone

unread,
May 10, 2014, 4:08:22 PM5/10/14
to kn...@googlegroups.com, Alex Perrone, h...@biostat.ucsf.edu
That's it. Thanks, Henrik! 

Carl Boettiger

unread,
May 10, 2014, 4:17:13 PM5/10/14
to Alex Perrone, knitr, h...@biostat.ucsf.edu
Or as documented in the knitr vignette on HTML, just set:

 opts_knit$set(upload.fun = image_uri)

(note that what you're observing with externally linked images is the standard HTML mechanism for including images)
--
Carl Boettiger
UC Santa Cruz
http://carlboettiger.info/

Alex Perrone

unread,
May 10, 2014, 4:47:29 PM5/10/14
to kn...@googlegroups.com, Alex Perrone, h...@biostat.ucsf.edu
Carl, that did not seem to work in an Rpres (another issue I wondered about, i.e. how to make an Rpres portable in sense of embedding local images completely, not just a pointer to local file). 

I embedded an image in an Rpres with standard markdown syntax above. 

Then I added this chunk: 

```{r setup, include=FALSE}
# set global chunk options
opts_knit$set(upload.fun = image_uri)
```

But this behaved same as previously, e.g. when renaming the PNG file, the image would no longer show up. So it was not embedded in a self-contained way. Do you have any idea how to do this? 

Thanks for your original tip.

Carl Boettiger

unread,
May 11, 2014, 2:31:38 PM5/11/14
to Alex Perrone, knitr, h...@biostat.ucsf.edu
Hi Alex,

I'm afraid I cannot reproduce what you describe.  I believe RStudio uses base64 encoding by default for all html outputs (e.g., if you generate the html of RStudio's Rpres using RStudio's more->save as webpage option. Perhaps you are generating html version in some other way? 


If I add the above chunk at the top of an Rpres, the .md file created by markdown does indeed have the image url embedded:

as you can see in that .md, the image is not linked in the usual way but instead embedded as a bunch of stand-alone binary content.  HTML created from this by any parser will thus also have the image embedded. 






--
You received this message because you are subscribed to the Google Groups "knitr" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knitr+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alex Perrone

unread,
May 11, 2014, 6:27:17 PM5/11/14
to kn...@googlegroups.com, Alex Perrone, h...@biostat.ucsf.edu
Right, we are on the same page. I'm also using the default Rpres provided by RStudio with More > Save as webpage. However, as I mentioned, I'm referring to embedding a local image, not producing a plot with R code, i.e. a line such as 

![](/path/to/my_image.png)

(or <img src="/path/to/my_image.png">)

in the Rpres. The reason I have this is that I have already produced plots from several parts of my project and have saved them out, and don't need/want to combine all the (not always fast) code from various places to re-generate the plots that I already have saved to disk as PNGs. So I just want to embed the local PNG files, but have it be portable, otherwise I'm tied to my machine and can't even share it with others (they won't see the plots that are still pointing to my local PNGs obviously). 

The pandoc flag --self-contained worked for Rmd -> knit to md -> pandoc dzslides, but the knitr chunk you provided was not having the same effect as truly embedding the image.  It would also help for this to work because --self-contained in pandoc is not compatible with mathjax. 

Does that all make sense?

Alex Perrone

unread,
May 11, 2014, 6:34:24 PM5/11/14
to kn...@googlegroups.com, Alex Perrone, h...@biostat.ucsf.edu
To clarify what exactly I'm doing, I take the precise default Rpres you uploaded Carl, which sets upload.fun, but then I add a single line: 

![](/path/to/my_image.png)

After the html is generated, I change the name of my_image.png to my_image2.png and see if the image is still visible in the html. This mimicks not having the image anymore (other options would be to move it, delete it, or try the html out on another machine, but this seemed easiest).

This procedure succeeded (could see the image) with knitting to md then using pandoc --self-contained, but the knitr chunk `opts_knit$set(upload.fun = image_uri)` did not succeed (image not visible) indicating it's not portable.

Yihui Xie

unread,
May 11, 2014, 7:11:23 PM5/11/14
to Alex Perrone, knitr, Henrik Bengtsson
You probably have some special characters in the path (e.g. spaces),
which can fail base64 encoding. I remember we fixed this problem in a
certain version of RStudio, and you might be using an old version. Can
you try the current version? http://www.rstudio.com/ide/download/

Regards,
Yihui
--
Yihui Xie <xiey...@gmail.com>
Web: http://yihui.name


Message has been deleted

Carl Boettiger

unread,
May 11, 2014, 9:34:19 PM5/11/14
to Alex Perrone, knitr, h...@biostat.ucsf.edu
Alex,

Ah, thanks for clarifying.  If knitr isn't generating the image, than of course any knitr settings have no effect.  It's important to keep in mind what tools are doing what. 

Knitr is not a markdown parser, it isn't touching your markdown.  It's just turning your R code chunks into the desired output (in this case, markdown).  When knitr sees some markdown code like

![](/path/to/my_image.png)

it just leaves it as is, because it's not an R chunk.  Just like any other markdown text. Does that make sense?  So then of course the image_uri setting has no effect. 

Pandoc, unlike knitr, is a markdown parser, so it reads all the markdown.  

Sounds like all you need is to convert your existing, non-knitr generated images to base64.  You can do that in R, e.g. by using the function that knitr is using in image_uri (markdown:::.b64EncodeFile, or just copy-paste the data-uris generated by pandoc back into your markdown).  

Pandoc --selfcontained is not imcompatible with Mathjax.  It is incompatible with the `--mathjax` flag because you cannot make the whole externally linked mathjax javascript library into a data URI. 


Alex Perrone

unread,
May 11, 2014, 10:10:09 PM5/11/14
to kn...@googlegroups.com, Alex Perrone, h...@biostat.ucsf.edu
Carl, 

Brilliant! That solves it. Specifically, in the Rpres markdown (i.e. outside of a knitr chunk) I replaced 

![](/path/to/my_image.png)  

by 

<img src=`r markdown:::.b64EncodeFile("/path/to/my_image.png")`>

which I consider slightly sneaky ;) But it seems to do the job! Thank you so much for your reply. It cleared everything up. 

-- Alex

Yihui Xie

unread,
May 13, 2014, 11:36:52 AM5/13/14
to Alex Perrone, knitr, Henrik Bengtsson
Is there a reason to use the absolute path? I'm not very sure if it is
relevant, but can you try the relative path instead? Relative paths
should be preferred whenever you can, since absolute paths are not
portable.

Regards,
Yihui
--
Yihui Xie <xiey...@gmail.com>
Web: http://yihui.name


On Sun, May 11, 2014 at 7:20 PM, Alex Perrone <alexp...@gmail.com> wrote:
> Using RStudio 0.98.507,
> R version 3.1.0 (2014-04-10) Platform: x86_64-apple-darwin10.8.0 (64-bit),
> knitr 1.5.
> No spaces or any other special characters in file name or file path. Exact
> Rpres in this gist, please change path to your image to see if it's portable
> for you (for this minimal one, when file name of PNG is changed, image no
> longer visible):
>
> https://gist.github.com/alexperrone/7bed0f960da16f56ea23

Alex Perrone

unread,
May 13, 2014, 11:52:27 AM5/13/14
to kn...@googlegroups.com, Alex Perrone, Henrik Bengtsson
That's a good point, though my main goal was to make the HTML output presentation portable  -- say if I have to all of the sudden present on a different machine, or want to email the HTML presentation to someone as if it's a powerpoint (which are self-contained). Though yes I agree, I might as well make the code itself as reproducible as possible as well. Thank you for your comment, and I very much admire the knitr package.

Alex
Reply all
Reply to author
Forward
0 new messages