EpiMan
EpiMan

Reputation: 839

How to merge images into one file in a defined order

I have around 100 images(png). Instead of doing that manually, I want to put them beside each other (12 images per line) in one single pdf in a defined order (based on file names).

Does anybody have any suggestion?

I tried according to what Thomas told me below, it paste them beside with a black margin, how can I remove that?

setwd(workingDir);
files <- list.files(path=".", pattern="*.png", all.files=T, full.names=T)
filelist <- lapply(files, readPNG)
names(filelist) <- paste0(basename((files)))
list2env(filelist, envir=.GlobalEnv)


par(mar=rep(0,4))
layout(matrix(1:length(names(filelist)), ncol=15, byrow=TRUE))

for(i in 1:length(names(filelist))) {
  img <- readPNG(names(filelist[i]))
  plot(NA,xlim=0:1,ylim=0:1,xaxt="n",yaxt="n")
  rasterImage(img,0,0,1,1)
}


dev.print(pdf, "output.pdf") 

Upvotes: 7

Views: 17134

Answers (3)

user144127
user144127

Reputation: 11

Sometimes you just want to put a bunch of PNG images into a PDF file, one image per page, for quick and easy viewing of them using a PDF reader. Here is how I did it, building on the above solution, and shrinking the image if necessary to fit the output PDF (but preserving the aspect ratio). This allows you to easily bundle PNG images of various sizes.

library(png)
# Define a function to get the xright and ytop arguments for rasterImage()
get.raster.image.area.scaling <- function(pngfile) {
  imga <- attr(readPNG(pngfile, info=TRUE), "info")
  img.width <- imga$dim[1] / imga$dpi[1]  # width of PNG image in inches
  img.height <- imga$dim[2] / imga$dpi[2]  # height of PNG image in inches
  img.aspect <- img.height/img.width  # aspect ratio of PNG image
  ri <- list()
  if(img.width > my.width || img.height > my.height) {
    # shrink to fit output device page
    diff.width <- img.width - my.width
    diff.height <- img.height - my.height
    if(diff.width >= diff.height) {
      # shrink to fit width
      ri$width <- 1.0  # xright for rasterImage (fraction of device area)
      new.height <- img.aspect * my.width # (in)
      ri$height <- new.height/my.height  # ytop for rasterImage (fraction of device area)
    } else if(diff.height > diff.width) {
      # shrink to fit height
      ri$height <- 1.0  # ytop for rasterImage (fraction of device area)
      new.width <- my.height / img.aspect # (in)
      ri$width <- new.width/my.width  # xright for rasterImage (fraction of device area)
    } else stop("need to debug unexpected situation\n")
  } else {
    # no shrinking of PNG image needed
    ri$width <- img.width / my.width
    ri$height <- img.height / my.height
  }
  return(ri)
}  # end of get.raster.image.area.scaling()

pngfiles <- c("yourfile1.png", "yourfile2.png", "yourfile3.png")
num.png <- length(pngfiles)
my.width <- 8  # dimensions of desired PDF device output (in)
my.height <- 10
pdf(file = "testplot.pdf", width=my.width, height=my.height, pointsize=12)
par(mai=rep(0,4)) # no margins
for(i in 1:num.png) {
  img <- readPNG(pngfiles[i], native=TRUE)
  ri <- get.raster.image.area.scaling(pngfiles[i])
  plot(NA, xlim=0:1, ylim=0:1, bty="n", axes=0, xaxs = 'i', yaxs='i')
  rasterImage(img, 0, 0, ri$width, ri$height)
}
dev.off()

Upvotes: 1

Dan Woodrich
Dan Woodrich

Reputation: 216

Note that the solution outlined by Thomas introduces some whitespace into the multipane image not present in the source image. Adding the arguments xaxs = 'i' and yaxs='i' into plot() will remove it.

library("png") # for reading in PNGs

# example image
img <- readPNG(system.file("img", "Rlogo.png", package="png"))

# setup plot
dev.off()
par(mai=rep(0,4)) # no margins

# layout the plots into a matrix w/ 12 columns, by row
layout(matrix(1:120, ncol=12, byrow=TRUE))

# do the plotting
for(i in 1:120) {
  plot(NA,xlim=0:1,ylim=0:1,bty="n",axes=0,xaxs = 'i',yaxs='i')
  rasterImage(img,0,0,1,1)
}

# write to PDF
dev.print(pdf, "output.pdf")

result image

Upvotes: 8

Thomas
Thomas

Reputation: 44525

You can plot them all together using the rasterImage function and the png package. Here's a simple showing how to read in a PNG and then plot it (a bunch of times).

library("png") # for reading in PNGs

# example image
img <- readPNG(system.file("img", "Rlogo.png", package="png"))

# setup plot
par(mar=rep(0,4)) # no margins

# layout the plots into a matrix w/ 12 columns, by row
layout(matrix(1:120, ncol=12, byrow=TRUE))

# do the plotting
for(i in 1:120) {
    plot(NA,xlim=0:1,ylim=0:1,xaxt="n",yaxt="n",bty="n")
    rasterImage(img,0,0,1,1)
}

# write to PDF
dev.print(pdf, "output.pdf")

You would need to modify this slightly so that it calls each image object, rather than just plotting img over and over again.

Result:

enter image description here

Upvotes: 11

Related Questions