DEV Community

Cover image for Optimize your images with R and reSmush.it
dieghernan
dieghernan

Posted on Originally published at dieghernan.github.io on

Optimize your images with R and reSmush.it

The resmush package has recently been accepted on CRAN! This small utility package allows for the optimization (i.e., compression) of local and online images using reSmush.it.

You can install resmush from CRAN with:

install.packages("resmush")
Enter fullscreen mode Exit fullscreen mode

This post was featured in episode 152 of R Weekly Highlights.

What is reSmush.it?

reSmush.it is a free online API that provides image optimization and has been implemented in WordPress, Drupal and Magento. Some features of reSmush.it include:

  • Free optimization services, no API key required.
  • Optimization of local and online images.
  • Supported image file formats: PNG, JPG/JPEG, GIF, BMP, TIFF, WebP.
  • Maximum image size: 5 MB.
  • Compression using several algorithms:
    • PNGQuant: Strip unneeded chunks from PNGs while preserving full alpha transparency.
    • JPEGOptim: Lossless optimization based on optimizing the Huffman tables.
    • OptiPNG: png reducer used by several online optimizers.

Why the resmush package?

One of the main reasons I developed resmush is because I usually include precomputed vignettes with my packages (see tidyterra as an example). I found that the plots created on CRAN with the standard configuration (i.e., not precomputed vignettes but built on CRAN itself) were not very satisfying. In some of the packages I developed, especially those related to mapping, they didn’t do justice to the actual results when a user runs them.

Precomputing vignettes has the drawback of producing higher-quality images at the expense of size. To avoid exceeding CRAN’s 5 MB maximum size policy, I developed resmush, which enables me to reduce the size of the images without a significant loss in quality.

Another use case for resmush is optimizing images in the context of web page development and SEO optimization. For example, I optimized all the images on this blog using resmush_dir(), which is a shorthand for optimizing all files in a specific folder.

There are other alternatives that I discuss at the end of this post, but briefly, the reSmush.it API works quickly with minimal configuration for a wide range of formats without needing an API key.

Using the resmush package

With local files

Let’s present an example of how a local file can be optimized. First, we create a large plot with ggplot2.

library(tidyterra)
library(ggplot2)
library(terra)
library(maptiles)

cyl <- vect(system.file("extdata/cyl.gpkg", package = "tidyterra")) %>%
  project("EPSG:3857")
cyl_img <- get_tiles(cyl, "Esri.WorldImagery", zoom = 8, crop = TRUE)
cyl_gg <- autoplot(cyl_img, maxcell = Inf) +
  geom_spatvector(data = cyl, alpha = 0.3)

cyl_gg
Enter fullscreen mode Exit fullscreen mode
Satellite map of Castile and Leon with a translucent regional boundary overlay, before image optimization.

Original satellite image before optimization.


# And we save it for resmushing
ggsave("cyl.png", width = 5, height = 0.7 * 5)
Enter fullscreen mode Exit fullscreen mode

The file has a size of 1.7 MB. We can use resmush_file() to reduce it:

library(resmush)
resmush_file("cyl.png")
#> ══ resmush summary ══════════════════════════════════════════
#> ℹ Input: 1 file with size 1.7 Mb
#> ✔ Success for 1 file: Size now is 762.2 Kb (was 1.7 Mb). Saved 948.9 Kb (55.46%).
#> See result in directory '.'.

# Check
png::readPNG("cyl_resmush.png") %>%
  grid::grid.raster()
Enter fullscreen mode Exit fullscreen mode
Satellite map of Castile and Leon with a translucent regional boundary overlay, after image optimization.

Satellite image after optimization with resmush_file().

By default, resmush_file() and resmush_dir() do not overwrite the original file, although this behavior may be modified with the overwrite = TRUE parameter. Now, the optimized file ("cyl_resmush.png") has a size of 762.2 kB.

Let’s compare the results side-by-side:

Satellite map of Castile and Leon with a translucent regional boundary overlay, before image optimization. Satellite map of Castile and Leon with a translucent regional boundary overlay, after image optimization.

The original image (left/top) is 1.7 MB. The optimized image (right/bottom) is 762.2 kB, a 55.46% reduction in file size. Click either image to enlarge.

We can verify that the image has been compressed without reducing its dimensions.

size_src <- file.size("cyl.png") %>%
  `class<-`("object_size") %>%
  format(units = "auto")
size_dest <- file.size("cyl_resmush.png") %>%
  `class<-`("object_size") %>%
  format(units = "auto")

dim_src <- dim(png::readPNG("cyl.png"))[1:2] %>% paste0(collapse = "x")
dim_dest <- dim(png::readPNG("cyl_resmush.png"))[1:2] %>% paste0(collapse = "x")

data.frame(
  source = c("original file", "compressed file"),
  size = c(size_src, size_dest),
  dimensions = c(dim_src, dim_dest)
) %>%
  knitr::kable()
Enter fullscreen mode Exit fullscreen mode
source size dimensions
original file 1.7 Mb 1050x1500
compressed file 762.2 Kb 1050x1500

With online files

We can also optimize online files with resmush_url() and download them to disk. In this example, I demonstrate a feature of all the functions in resmush: they return an invisible data frame with a summary of the process.

url <- "https://dieghernan.github.io/assets/img/samples/sample_1.3mb.jpg"

# Invisible data frame
dm <- resmush_url(url, "sample_optimized.jpg", report = FALSE)
Enter fullscreen mode Exit fullscreen mode
knitr::kable(dm)
Enter fullscreen mode Exit fullscreen mode
src_img dest_img src_size dest_size compress_ratio notes src_bytes dest_bytes
https://dieghernan.github.io/assets/img/samples/sample_1.3mb.jpg sample_optimized.jpg 1.3 Mb 985 Kb 26.63% OK 1374693 1008593
Colorful illustration of sunset over ocean waves and a beach, before image optimization. Colorful illustration of sunset over ocean waves and a beach, after image optimization.

The original image (left/top) is 1.3 MB. The optimized image (right/bottom) is 985 kB, a 26.63% reduction in file size. Click either image to enlarge.

Other alternatives

There are other alternatives for optimizing images with R, but first…

Yihui Xie, one of the most prominent figures in the R community, was recently laid off from his position at Posit PBC (formerly RStudio) (more info here).

Yihui is the developer of knitr, markdown, blogdown and bookdown, among others, and he has been one of the key contributors (if not the most important) to the reproducible research space with R through his libraries.

If you have ever used and enjoyed his packages, consider sponsoring him on GitHub.

Sponsor Yihui Xie

  • One of the many packages developed by Yihui is xfun, which includes the following functions for optimizing image files:
    • xfun::tinify() is similar to resmush_file() but uses TinyPNG. An API key is required.
    • xfun::optipng() compresses local files with OptiPNG (which needs to be installed locally).
  • tinieR package by jmablog. An R package that provides a full interface with TinyPNG.
  • optout package by @coolbutuseless. Similar to xfun::optipng() with additional options. Requires additional software to be installed locally.
Table 1: R packages: Comparison of alternatives for optimizing images.
tool CRAN Additional software? Online? API Key? Limits?
xfun::tinify() Yes No Yes Yes 500 files/month (Free tier)
xfun::optipng() Yes Yes No No No
tinieR No No Yes Yes 500 files/month (Free tier)
optout No Yes No No No
resmush Yes No Yes No Max size 5Mb
Table 2: R packages: Supported formats.
tool png jpg gif bmp tiff webp pdf
xfun::tinify() ✅ ✅ ❌ ❌ ❌ ✅ ❌
xfun::optipng() ✅ ❌ ❌ ❌ ❌ ❌ ❌
tinieR ✅ ✅ ❌ ❌ ❌ ✅ ❌
optout ✅ ✅ ❌ ❌ ❌ ❌ ✅
resmush ✅ ✅ ✅ ✅ ✅ ✅ ❌

Additionally, if you host your projects on GitHub, you can try Imgbot, which is free for open-source projects. Imgbot provides automatic optimization for files in your repositories, and the optimized files will be included in specific pull requests before merging into your work.

Top comments (0)