rstudio / webshot2

Take screenshots of web pages from R
https://rstudio.github.io/webshot2/
111 stars 17 forks source link

`expand` argument of `webshot()` not working as expected #67

Open Teebusch opened 1 month ago

Teebusch commented 1 month ago

The documentation states that expand lets me add a fixed number of pixels to the clipping rectangle:

expand A numeric vector specifying how many pixels to expand the clipping rectangle by. If one number, the rectangle will be expanded by that many pixels on all sides. [...] https://rstudio.github.io/webshot2/reference/webshot.html

In the following reprex expand seems to have no effect

library(htmltools)

fn_html <- 'test.html'
fn_img <- 'test.png'
url <- paste0('file://', here::here(fn_html))

tags <- htmltools::tags

# -- setup html to capture: a 100x100px square box

tags$body(
  tags$div(style = "width: 100px; height: 100px; background-color: red"),
  style = "margin: 0;"   # chrome browser default is `margin: 8px`
) |> 
  as.character() |> 
  writeLines(con = file(fn_html))

# -- trying to get `expand` to work

webshot2::webshot(
  url = url,
  file = fn_img,
  vwidth = 100,     
  vheight = 100
)
utils::browseURL(fn_img)  # result: 100x100px (as expected)

webshot2::webshot(
  url = url,
  file = fn_img,
  vwidth = 100,     
  vheight = 100,
  expand = 200            # expectation: add 200px on each side
)
utils::browseURL(fn_img)  # result: 100x100px - expand has no effect on size

webshot2::webshot(
  url = url,
  file = fn_img,
  vwidth = 100,     
  vheight = 100,
  cliprect = c(0,0,50,50),
  expand = 200             # expectation: add 200px on each side
)
utils::browseURL(fn_img)   # result: 50x50px (= `cliprect`) - expand has no effect on size
gadenbuie commented 1 month ago

Thanks @Teebusch. We definitely need to update the documentation to better call out the role of the expand argument. It only comes into play when the clipping rectangle is determined by selector. In other words, you can provide a selector plus an extra area to expand, or you can directly provide a cliprect value.

Teebusch commented 1 month ago

Thank you! There seems to be a bit more to it than just using selector, because this also doesn't work:

library(htmltools)
tags  <- htmltools::tags

fn_html <- 'test.html'
fn_img <- 'test.png'
url <- paste0('file://', here::here(fn_html))

tags$body(
  tags$div(
    id = 'mydiv',            # <-- this will be used as selector for webshot
    style = "width: 100px; height: 100px; background-color: red;"
  ),
  style = "margin: 0px;"   # chrome browser default is `margin: 8px`
) |> 
  as.character() |> 
  writeLines(con = file(fn_html))

webshot2::webshot(
  url = url,
  file = fn_img,
  selector = '#mydiv',
  vwidth = 100,     
  vheight = 100,
  expand = 200            # expectation: add 200px on each side
)

# result: 100x100px, no  effect of `expand`

magick::image_read(fn_img)

#   format width height colorspace matte filesize density
#   <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
# 1 PNG      100    100 sRGB       FALSE      300 72x72  

Edit

This works, so it seems like you also shouldn't use vwidth and vheight if you use selector:

# ... until here same as above 

webshot2::webshot(
  url = url,
  file = fn_img,
  selector = '#mydiv',
  expand = 200            # expectation: add 200px on each side
)

# OK 
magick::image_read(fn_img)

#   format width height colorspace matte filesize density
#   <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
# 1 PNG      300    300 sRGB       FALSE      300 72x72  

This only works if the selected element has fixed dimensions. If, in the example above, #mydiv has height/width set to 100% the image will have the default viewport dimensions (992x744).

gadenbuie commented 1 month ago

There seems to be a bit more to it than just using selector ... it seems like you also shouldn't use vwidth and vheight if you use selector.

That's right, the clipping rectangle doesn't expand past the virtual boundaries of the screen. In your first example, the virtual screen size is the exact same size as #mydiv, so the screenshot can only be at most 100x100.

In your second example, notice that the clipping rectangle is expanded only on the right and bottom sides of #mydiv. (I changed the page background color slightly for visibility.)

image

If you give #mydiv additional margin, e.g. margin: 200px, you'll have a square with 100 + 200 + 200 = 500px per side.

tags$body(
  tags$div(
    id = 'mydiv',
    style = "margin: 200px; width: 100px; height: 100px; background-color: red;"
  ),
  style = "margin: 0px; background-color: #f3f3f3"
) |> 
  as.character() |> 
  writeLines(con = file(fn_html))

webshot2::webshot(
  url = url,
  file = fn_img,
  selector = '#mydiv',
  expand = 200
)

magick::image_read(fn_img)
#> # A tibble: 1 × 7
#>   format width height colorspace matte filesize density
#>   <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
#> 1 PNG      500    500 sRGB       FALSE     1870 72x72  

image

Teebusch commented 1 month ago

That makes sense! Thank you for taking the time to elaborate!