library(gdalraster)
#> GDAL 3.13.0dev-0e4f0cadf6 (released 2026-01-20), GEOS 3.12.1, PROJ 9.7.0
dsn <- "WMTS:https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/WMTS/1.0.0/WMTSCapabilities.xml,layer=World_Imagery"
ds <- new(GDALRaster, dsn)
d <- read_ds(ds, out_xsize = 1024, out_ysize = 1024, bands = 1:3)
bb <- ds$bbox()
plot(NA, xlim = bb[c(1, 3)], ylim = bb[c(2, 4)], asp = 1, xlab = "", ylab = "")
a <- aperm(array(d, c(1024, 1024, 3)), c(2,1 ,3))
a01 <- a/255
system.time({
rasterImage(a01, bb[1], bb[2], bb[3], bb[4])
})
#> user system elapsed
#> 0.212 0.024 0.238
native_rgb <- function(r, g, b, dm) {
#res <- bitwOr(bitwOr(bitwOr(r, bitwShiftL(g, 8L)), bitwShiftL(b, 16L)), -16777216L)
res <- as.integer(r) + as.integer(g) * 256L + as.integer(b) * 65536L - 16777216L
res <- matrix(res, dm[2L], dm[1L], byrow = TRUE)
class(res) <- "nativeRaster"
attr(res, "channels") <- 3L
res
}
b <- native_rgb(a[,,1L], a[,,2L], a[,,3L], c(1024, 1024))
system.time({
rasterImage(b, bb[1], bb[2], bb[3], bb[4])
})#> user system elapsed
#> 0.001 0.000 0.001
Created on 2026-01-22 with reprex v2.0.2


Very nice. Always appreciate your examples.
Small detail... when using MEM the dataset doesn't actually have a real file name. It's held in a memory allocation managed by the driver and not in /vsimem. I usually pass either an empty string or something like "in-memory raster" for the filename argument. It's possibly better not to pass a real filename to avoid confusion because the string that you pass to
create()for example, will appear as the "DSN" value from the object'sshow()method. That's because I set it here https://github.com/firelab/gdalraster/blob/ebada5f2a1eb17eda8170fb1c9ddbf458eba02a0/src/gdal_exp.cpp#L847 and it then gets set as the GDAL dataset-level Description, which is whatshow()reports. Normally that's the dataset's filename. MEM is the exception, but minor detail.Since
nativeRastercan be passed torasterImage(), it seems likegdalraster::plot_raster()could have a code path accepting anativeRasterinput, then we wouldn't need the helper function. I was going to look into that once I have a chance to experiment.