Reputation: 839
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
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
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")
Upvotes: 8
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:
Upvotes: 11