gt icon indicating copy to clipboard operation
gt copied to clipboard

`as_raw_html()` doesn't include images

Open bzigterman opened this issue 2 years ago • 1 comments

When I run the code below to make an html table with gt, the images appear fine in Rstudio's viewer, but when I run them through as_raw_html, the image references don't make it into the html. Unless I'm doing something wrong, this appears to be a bug in gt.

This also happens when I use local_image. Curiously, it doesn't happen when I add inline_css = FALSE to as_raw_html.

library(gt)
library(tidyverse)

standings_table <-
  dplyr::tibble(
    pixels = px(seq(10, 35, 5)),
    image = seq(10, 35, 5)
  ) %>%
  gt() %>%
  text_transform(
    locations = cells_body(columns = image),
    fn = function(x) {
      web_image(
        url = "https://www.mlbstatic.com/team-logos/142.svg",
        height = as.numeric(x)
      )
    }
  )

standings_table
standings_table_html <- as_raw_html(standings_table)
standings_table_html

bzigterman avatar Sep 13 '21 16:09 bzigterman

Thanks for filing this issue! This appears to be a problem with the inlining codepath and it does require fixing such that image data is preserved.

rich-iannone avatar Nov 04 '21 16:11 rich-iannone

I have encountered this problem too, but I wonder if it is related to the size of the image (i.e., the number of characters in the data URI). See below for a minimal working example. What seems to happen is that the smaller image ('dot') is included but the larger one is not.

library(tidyverse)
library(gt) # gt_0.7.0

images <- c(dot = '<img src="data:image/png;base64,iVBORw0KGgoAAA
ANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU
5ErkJggg=="/>',
            test = local_image(file = test_image(type = "png")))

tibble(
  name = names(images),
  image = 1:2
) %>%
  gt() %>%
  text_transform(
    locations = cells_body(columns = image),
    fn = function(x) {
      images[as.numeric(x)]
    }
  ) ->
  my_table

print(my_table) # OK: Displays both images in the RStudio Viewer

stopifnot(str_count(as_raw_html(my_table, inline_css = FALSE), pattern = '<img') == 2) # OK
stopifnot(str_count(as_raw_html(my_table), pattern = '<img') == 2) # Fails! Only 'dot' image appears

banbh avatar Oct 18 '22 15:10 banbh

If it were related to the number of characters in the transformed cell then the code below should reproduce it (and find roughly where it breaks). However, the code below seems to work as expected (i.e., even a very long sequence of "x"s faithfully appears in the output of as_raw_html(). As a result, I'm not sure what is going on.

# A continuation of my previous code
print(log2(nchar(images)))

nums <- seq(5, 16, len = 5)

tibble(nums, xs = seq_along(nums)) %>%
  gt() %>%
  text_transform(
    locations = cells_body(columns = xs),
    fn = function(x) {
      print(x)
      n <- 2^nums[as.numeric(x)]
      print(n)
      paste0('<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAM', 
             strrep('x', n), 
             '4WLNzJwAAAAABJRU5ErkJggg==" />')
    }) ->
  my_table2

stopifnot(str_count(as_raw_html(my_table2), '<img')==length(nums)) # OK

banbh avatar Oct 18 '22 18:10 banbh

I think I've isolated an important difference between the two images in my images vector. The first one (the red dot) end the tag with /> while the second ends with just > (see str_sub(images, -2)). Is it possible the as_raw_html() expects tags to be closed?

banbh avatar Oct 18 '22 19:10 banbh

I think my previous comment (regarding /> vs >) is wrong -- it makes no difference.

What does seem to make a difference is

  • the absence of a style attribute on the img tag, or
  • the presence of a newline ('\n') in the data.

If either of the above two conditions are met then as_raw_html() will emit the img tag. For example, line (2) below inserts a newline after char 40 and (surprisingly) that results in the img showing up in the html.

library(tidyverse)
library(gt) # gt_0.7.0

images <- c('<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" style="">',
            local_image(file = test_image(type = "png")))

# Below, if line (1) or (2) (or both) are executed then both images show up in html, otherwise neither show up.
images <- str_remove(images, ' style=".*"') # (1)
images <- str_replace(images, '^(.{40})(.*)$', '\\1\n\\2') # (2)

tibble(name = c('dot','test'), image = seq_along(name)) %>%
  gt() %>%
  text_transform(
    locations = cells_body(columns = image),
    fn = function(x) images[as.numeric(x)]) ->
  my_table

print(my_table) # OK: Displays both images

stopifnot(str_count(as_raw_html(my_table), pattern = '<img') == 2) # If (1) or (2) are executed then this succeeds, otherwise fails

banbh avatar Oct 18 '22 22:10 banbh