New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Including image using blogdown #45

Closed
janeshdev opened this Issue Jan 25, 2017 · 23 comments

Comments

Projects
None yet
@janeshdev
Copy link

janeshdev commented Jan 25, 2017

I am struggling to include the image using blogdown. Specifically where should I store my image ?
I am using the following structure but the image is not displayed. I have saved the image on the post folder.

* This is the image : 
![My picture](pic1.PNG)

The output looks like:
image

Can anyone tell me where should I store the image and the proper syntax to use?

@maxheld83

This comment has been minimized.

Copy link

maxheld83 commented Jan 25, 2017

just store the image in static/img/pic1.png and then include it by ![My picture](img/pic1.png).
Works for me.
Notice though that R / blogdown never touch this; that's just basic markdown/HUGO.
So there's no special blogdown sauce for doing this AFAIK.

(Ps.: the img folder is not technically necessary; just seems to be a HUGO convention.)

@janeshdev

This comment has been minimized.

Copy link

janeshdev commented Jan 25, 2017

@maxheld83 Thank you for your response. I did what you proposed. But I am still not being able to see the image. Btw I am using wamp server to view my blog generated from blogdown.

@pssguy

This comment has been minimized.

Copy link

pssguy commented Jan 25, 2017

@janeshedev I had problems with this too some time ago and meant to get back to it. As a hack, I found that creating an img folder in public and then putting images in there and referencing this way worked

<img src="../../img/mypic.png" alt="" />

But I think this is likely to cause more problems so I'm not recommending it

@yihui

This comment has been minimized.

Copy link
Member

yihui commented Jan 25, 2017

As @maxheld83 pointed out, I'd also recommend using the static/ folder. Everything under static/ will be copied to public/, so you can reference the image using /path/to/image.png (note the leading slash, without which the path will be relative) if this image is originally at static/path/to/image.png.

A relative path like @pssguy pointed out also works, but it is dependent on the location of the .html file, i.e. you have to count how many levels you have to go up (i.e. how many ../) from the directory of the .html file to find the image.

@janeshdev

This comment has been minimized.

Copy link

janeshdev commented Jan 25, 2017

@pssguy Thanks for the suggestion.
@yihui Yes that leading / (leading slash) did the trick. Now, the image is displayed properly.

@yihui

This comment has been minimized.

Copy link
Member

yihui commented Jan 25, 2017

Well, using an absolute path also has its drawback. For example, it works if you publish the website to example.com, but it won't work if you publish to a subdirectory like example.com/foo/ (in this case, the absolute path has to be /foo/path/to/image.png). Relative paths works everywhere, but the problem is as I mentioned -- you need to count how many levels you have to go up (if your .html is rendered to a different folder in the future, you may have to adjust the number of ../). Either way has its pros and cons. I'll just let you decide which way you want to go.

@janeshdev

This comment has been minimized.

Copy link

janeshdev commented Jan 26, 2017

Thanks for pointing out the advantages / disadvantages of both the approaches.

@skadauke

This comment has been minimized.

Copy link

skadauke commented Jun 7, 2017

The problem I have with using the static/ folder is that I like to see images displayed in the RStudio Editor while I am writing. For example, say I'm working on a post that includes the following image reference:

![](image.png)

And the directory structure is:

content/post/2017-06-06-imagetest.Rmd
content/post/image.png

Then RStudio will display the image without giving me an annoying error that the image cannot be found. However, with the default settings, blogdown + Hugo will then create:

public/2017/06/06/imagetest/index.html
public/post/image.png

Since the index.html file links to image.png but that image is no longer in the same folder, the web browser will show a broken image link.

It seems like what should happen is for Hugo to copy over image.png to public/2017/06/06/imagetest/ or else, update the reference, but neither happens.

I ended up solving this issue by making the following changes in config.toml:

uglyurls = true
#[permalinks]
# post = "/:year/:month/:day/:slug/"

Now blogdown/hugo creates:

public/post/imagetest.html
public/post/image.png

And everything works. I hope this helps anyone else struggling with getting images to work... and please let me know if there is a better way to do this!

@yihui

This comment has been minimized.

Copy link
Member

yihui commented Jun 7, 2017

@skadauke That is the best way if you do not use the Serve Site addin to preview your site in the RStudio Viewer but want to preview images right in the source editor.

@skadauke

This comment has been minimized.

Copy link

skadauke commented Jun 7, 2017

@yihui I guess I want both :)

dantonnoriega added a commit to dantonnoriega/ultinomics.org that referenced this issue Jun 21, 2017

@yihui

This comment has been minimized.

Copy link
Member

yihui commented Jun 23, 2017

I have finished the relevant documentation for this issue:

@yihui yihui closed this Jun 23, 2017

@taraskaduk

This comment has been minimized.

Copy link

taraskaduk commented Jan 10, 2018

@yihui is there a way to make blogdown copy objects from /content to /static?
In my /content folder, I store my posts in R projects in folders, so that the .Rmd file and all supporting data and files are stored in one place. Here, I'll also store any external pictures that aren't generated by my code.

What I understand now is that in order to include an external picture into my post, I need to do either one of 2 things:

  1. manually copy the picture into the /static folder
  2. play with the relative path, jumping up one step and them digging down again to exit the /static folder and go back to the /content folder.

Any better solutions you might suggest?

@missaugustina

This comment has been minimized.

Copy link

missaugustina commented Feb 27, 2018

I'm going to second the issues here. I've just spent over 3 hours trying to get this to work. I'm including files in my Rmd so I can generate plots as well as external images. The files fail if they can't find the path from within RStudio but once I get those to pass, the generated paths are preventing things from showing up. The docs aren't clear, or maybe they are to someone who is not trying to do this at 1am... but that's usually my baseline.

Here's my use case:

readRDS("myfile.RDS") <-- what path can I use that both RStudio and Hugo/blogdown will find and not error?

my image <-- what path can I use that both RStudio and Hugo/blogdown will find and render correctly?

@apreshill

This comment has been minimized.

Copy link
Member

apreshill commented Feb 27, 2018

Hi @missaugustina,

Messaged you on twitter too. As suggested in this thread, my recommendation is put all static files, like data files (.csv, .RDS, etc.) and images (.jpeg, .gif, .png) into the /static folder.

Images

For images referenced in a post, we discussed how to reference a file in that folder in the blogdown demo site and in the book.

You can also make files within the /static subfolder structure, like we did on the blogdown demo site. I also did this for our RLadies site.

The short story is that if you are in a post, Hugo looks for all external files in the /static folder by default. So if your image is called "piggie.png", that file should be in the /static folder for Hugo to find it. If you instead want to put "piggie.png" in the /static folder but inside of a subfolder called "images" (so /static/images), you would reference that file in your post with: /images/piggie.png (because it starts at /static as the root).

Data files

Now data files are a bit trickier, because your .Rmd post looks first in the same folder that the .Rmd file is, so it looks in /content/post first. Mara had a good answer here on this topic. There are 4 ways:

  1. Put your data files in /content/post and it will just work
  2. Put your data in /static instead. To reference that kind of file in an R chunk, you'll need to do ../../static.
  3. You can use the here package to build the file path (see below for example)
  4. You can upload your file to your git repo then use the raw url from GitHub to read in

Your two examples

readRDS("myfile.RDS") <-- what path can I use that both RStudio and Hugo/blogdown will find and not error?

Answer:

  • if "myfile.RDS" is in /static, the path you use in the post is ../../static/myfile.RDS
  • if "myfile.RDS" is in /static/data, the path you use in the post is ../../static/data/myfile.RDS
  • if using here package:
library(here)
libarary(readr)
mydata <- read_csv(here("static/data/", "myfile.csv"))
# or
myfile <- here("static/data/", "myfile.csv")
mydata <- read_csv(myfile)
  • if using a GitHub raw url:
mydata <- read_csv("https://gist.githubusercontent.com/kylebgorman/77ce12c9167554ade560af9d34565c11/raw/c5d653fb146821ecd96a9aa085263c3f17480dd5/McFarlaneEtAl_MazeData-Deidentified.csv")
# or
mylink <- "https://gist.githubusercontent.com/kylebgorman/77ce12c9167554ade560af9d34565c11/raw/c5d653fb146821ecd96a9aa085263c3f17480dd5/McFarlaneEtAl_MazeData-Deidentified.csv"
mydata <- read_csv(mylink)

my image <-- what path can I use that both RStudio and Hugo/blogdown will find and render correctly?

Answer:

  • if "myimage.png" is in /static, the path you use in the post is myimage.png
  • if "myimage.png" is in /static/images, the path you use in the post is /images/myimage.png

Does that help? Let me know 😍
If it does, I'll add a new post to the blogdown demo site 👍

@dracodoc

This comment has been minimized.

Copy link

dracodoc commented Mar 16, 2018

@yihui
After reading the discussion above, I'm wondering if it's possible to make things work as expected instead of ask users to understand the complex steps required now.

A RMarkdown should work in local rendering and rendered website in same way.

  • if we need to modify the document, manipulate folders, paths when converting a local rmd to blog, that's not optimal.
  • that will need more plumbing work in blogdown side to make things looks smooth for users.

What's the best way to do that plumbing work?

  • I'll suggest to make the assumption that each rmd can have one companion folder. For example report_1.rmd have a report_1_src_files folder in same level.
    • Organizing files related to a report is a complex topic, some users may have files in other folders. To make things under control we can assume it's reasonable to ask users to copy all files needed into one folder in same level with report at least for using blogdown.
  • User should just write the rmd like before, and rstudio can preview the image normally. The rmd can be knitted normally.
  • blogdown need to know that companion folder belong to that post first before it can deal with it properly. This can be done in several ways:
    • add an entry in rmd yaml header. This is simple and clear.
    • use some folder naming convention. I don't think this is a good idea. something like report_1_files can conflict with generated folder/files.
    • scan the rmd for local reference and determine the folder belong to the rmd. This approach have the advantage that user can use multiple folders. But I think this make things too complex.
      I think the yaml header method is simplest and best.
  • With the companion folder knowledge, blogdown can do the additional steps needed:
    • copy the folder to static. I'm not sure whether we should add more level for organization, but at least it should not be put in report_1_files folder to avoid conflict with generated files.
    • modify the links in rmd before rendering. I assume there are some preprocess to rmd and we can update links in this step, maybe save to a temporary file.
      • previously user should use relative path for files in companion folder, now they need to be either
        • relative path, with proper levels jumped
        • absolute path, this can be done with just adding / in beginning, if there is no subpath in website involved. I think blogdown should know about the subpath and can add it when needed.

If you think this direction is good, I'll try to look at the code and get a PR when I got more time.

@jimingshuo

This comment has been minimized.

Copy link

jimingshuo commented Mar 18, 2018

I started to use Blogdown two days ago, and this was exactly an issue bothered me when I tried to create my first post.

After several trials, I realize that Yihui and most of the people use Mac OS, while I am using Windows 10. And I believe Blogdown behaves differently in Windows OS. When I create a new post by using "Addins"->"New Post", Blogdown creates the *.RMD file in "../content/post" instead of "../static/post" folder, while ".." is my project folder. Under the "../static/post" folder, it actually contains the folder "2015-07-23-r-rmarkdown_files", which should be copied or compiled by RMarkdown during the installation of the package.

Once I save my images in "../content/post/img", then those images are available in my post.

image

@dracodoc

This comment has been minimized.

Copy link

dracodoc commented Mar 18, 2018

Hugo 0.32 start to support page bundles, which can include various assets with post together. However it's quite complex, and I don't think it's easy to use or familiar for Rmd workflow.

One simple hack could be just automate the manual tasks as much as possible:

  • write rmd in a draft folder, save assets files in a folder with same name of rmd (so there is no need to specify this folder), use relative path in rmd. Everything should work and can be previewed.
  • use script to copy the asset folder to static, and change the relative link in rmd to absolute link, copy rmd to content/post. This should ensure the post have correct links.
@gadenbuie

This comment has been minimized.

Copy link
Contributor

gadenbuie commented Mar 19, 2018

Version 0.6 of blogdown will include a new "Insert Image" RStudio Addin that makes it much easier to add images to blog posts. The feature is already available in the GitHub version of blogdown -- which you can install via devtools::install_github("rstudio/blogdown").

The addin was contributed by @lcolladotor and there is a nice introduction to it on his blog.

Hopefully this feature will help reduce the friction around the content and static directories. @apreshill would this be a good feature to highlight or add to the blogdown demo site?

@dracodoc

This comment has been minimized.

Copy link

dracodoc commented Mar 19, 2018

That will be great for the workflow of creating new post from scratch inside RStudio. Though I feel it's kind of extra effort because inserting an image in markdown format used to simple and don't need a GUI.

blogdown is limited by how hugo doing things, the page bundle feature in hugo looks too complex for me too.

@skadauke

This comment has been minimized.

Copy link

skadauke commented Mar 19, 2018

@gadenbuie I'm wondering if it's such a great idea to create functionality for blogdown only that should really be universal to all of R Markdown. At rstudio::conf I had briefly spoked to @yihui and suggested a feature that would allow dragging+dropping an image file or pasting an image from clipboard directly into the RStudio editor - and RStudio would automatically place a copy of the image in the correct place and insert the code to link to the image.

@dracodoc

This comment has been minimized.

Copy link

dracodoc commented Mar 20, 2018

This is the script I used to convert existing rmd:

  • assume asset folder is same name with rmd file name. don't use white space in file name
  • use / in path
  • I need to use absolute path in parameters because the site is not top level in my project, and servr have to change working directory to the site, so better use absolute path
  • this function will modify the asset folder link and save new rmd to post folder, copy asset folder to static
# it's better to use - or _ in file name instead of white space.
# press tab in link to refresh the rstudio preview
# need absoluate path because servr changed current working directory.
process_rmd <- function(rmd_path, site_path = ".") {
  # assume asset folder has same name of rmd name
  file_name <- basename(rmd_path)
  asset_folder <- substr(file_name, 1, nchar(file_name) - 4)
  # change relative path of assets folder to absolute path
  # to deal with encoding, there are some internal functions. just assume utf 8 here.
  # input_lines <- rmarkdown:::read_lines_utf8(rmd_path, getOption("encoding"))
  input_lines <- readLines(rmd_path)
  input_lines <- gsub(paste0("](", asset_folder, "/"), 
                      paste0("](/", asset_folder, "/"),
                      input_lines, fixed = TRUE)
  post_path <- file.path(site_path, "content", "post", file_name)
  writeLines(input_lines, post_path)
  # copy asset folder to static/. also assume using / instead of \
  asset_path <- file.path(dirname(rmd_path), asset_folder)
  static_path <- file.path(site_path, "static")
  file.copy(asset_path, static_path, recursive = TRUE)
}
@jimingshuo

This comment has been minimized.

Copy link

jimingshuo commented Mar 20, 2018

I think the best way to fix this is to update RMarkdown code, just find out where it says a new post should be saved in "contents" folder, and change that to "static", to keep the consistency for all OS.

@yihui

This comment has been minimized.

Copy link
Member

yihui commented Mar 20, 2018

Oh @skadauke you have come here. Apparently I didn't remember your name at rstudio::conf when you mentioned the idea to me, but I did remember your idea and mentioned it when @lcolladotor implemented the "Insert Image" addin: #272 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment