Using webp in R: A New Format for Lossless and Lossy Image Compression

January 25, 2016


A while ago I blogged about brotli, a new general purpose compression algorithm promoted by Google as an alternative to gzip. The same company also happens to be working on a new format for images called webp, which is actually a derivative of the VP8 video format. Google claims webp provides superior compression for both lossless (png) and lossy (jpeg) bitmaps, and even though the format is currently only supported in Google Chrome, it seems indeed promising.

The webp R package allows for reading/writing webp bitmap arrays so that we can convert between other bitmap formats. For example, let’s take this photo of a delicious and nutritious feelgoodbyfood spelt-pancake with coconut sprinkles and homemade espresso (see here for 7 other healthy winter breakfasts!)

We read the jpeg file into a bitmap and then write it to webp:

library(webp)
library(jpeg)
library(curl)
curl_download("https://www.opencpu.org/images/pancake.jpg", "pancake.jpg")
bitmap <- readJPEG("pancake.jpg")
write_webp(bitmap, "pancake.webp")

# Only works in Google Chrome
browseURL("pancake.webp")

Of course it works the other way around as well. To read the webp image back into a bitmap and write it to png:

library(png)
bitmap2 <- read_webp("pancake.webp")
writePNG(bitmap2, "pancake.png")
browseURL("pancake.png")

Rendering graphics to webp

The best way to write plots in webp format is using an svg device and then render to bitmap with the rsvg package:

# create an svg image
library(svglite)
library(ggplot2)
svglite("plot.svg", width = 10, height = 7)
qplot(mpg, wt, data = mtcars, colour = factor(cyl))
dev.off()

# render it into a high definition bitmap image
library(rsvg)
rsvg_webp("plot.svg", "plot.webp", width = 1920)
browseURL("plot.webp")

The write_webp function has a quality parameter (integer between 1 and 100) which can be used to tune the quality-size trade-off for lossy compression. A quality=100 equals lossless compression; the default quality=80 provides considerable size reduction with negligible loss of quality.

library(rsvg)
library(webp)
tiger <- rsvg("http://dev.w3.org/SVG/tools/svgweb/samples/svg-files/tiger.svg", height = 720)
write_webp(tiger, "tiger100.webp", quality = 100)
write_webp(tiger, "tiger80.webp", quality = 80)
write_webp(tiger, "tiger50.webp", quality = 50)

Unfortunately webp will probably not become mainstream until it gets implemented by all browsers. But performance seems pretty good so perhaps it could actually be useful for large image compression in scientific applications.