I'm using the following code to add an image to a ggplot object and set the alpha (transparency) to 0.5
add_BGimg <- function(bg_image_in, res, ggplot_in){
im <- png::readPNG(bg_image_in)
im2 <- matrix(grDevices::rgb(im[,,1],im[,,2],im[,,3], im[,,4] * 0.5), nrow=dim(im)[1]) ## you can change 0.5 to change the alpha
ggplot_in <-
ggplot_in +
annotation_custom(grid::rasterGrob(im2),
xmin = res[1],
xmax = res[2],
ymin = res[3],
ymax = res[4])
return(ggplot_in)
}
This works well for many images, but I've come across some images that appear not to have a transparency layer. At least that's what I'm guessing is the problem, as I'm getting:
Error in img[4, , ] : subscript out of bounds
Ideally I'd like all images passed to have transparency - is there a way to add this layer? Or a better way to handle a wider range of image formats?
As @M-- noted, not all PNGs have an alpha channel. You may not know a priori when it will, but after png::readPNG
you can change for the fourth layer in the 3-dim array.
im <- png::readPNG("image.png")
im2 <- png::readPNG("image_no_alpha.png")
dim(im)
# [1] 999 2727 4
dim(im2)
# [1] 999 2727 3
One can add a a fully-opaque layer using the abind::
package:
if (dim(im)[3] == 3) {
im <- abind::abind(im, matrix(1, ncol=ncol(im), nrow=nrow(im))) –
}
Admittedly that's a rather focused if
conditional, assuming (1) im
has 3 dimensions, and (2) the third axis will have either 3 or 4, never 2 or 5. Note that from ?readPNG
:
Most common files decompress into RGB (3 channels), RGBA (4
channels), Grayscale (1 channel) or GA (2 channels). Note that G
and GA images cannot be directly used in rasterImage unless
‘native’ is set to ‘TRUE’ because rasterImage requires RGB or
RGBA format (‘nativeRaster’ is always 8-bit RGBA).
This suggests that you may want to guard better against how many channels are encoded in the file. You might be a little defensive to say stopifnot("fewer than 3 channels" = dim(im)[3] < 3)
.