gt
gt copied to clipboard
`as_raw_html()` doesn't include images
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
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.
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
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
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?
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 theimg
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