R で作成された PDF 画像を LaTeX で使う
EPS ファイルにあるバウンディングボックスの値は,PDF ファイルや PNG, JPG ファイルにはない。そのため,画像の大きさを確認して,手作業でバウンディングボックスの値を確定しないといけない。でも,foo.bb というファイルがあれば,そして,foo.bb を自動作成できればそのような手間が省ける。
追記2010.04.09 Unix には BoundingBox の値を画像ファイルから抜き出す命令がある。Windows 用の命令もあるらしい。参考
foo.bb の中身は簡単なもの。以下のようなものの3行目だけが必要。
%%Title: ./foo.jpg %%Creator: Rebb Version 0.0.1 %%BoundingBox: 0 0 410 350 %%CreationDate: Fri Apr 16 14:34:24 2010
河童の屁が補足 2010/04/14
R が作る pdf に対しては ebb は以下のようなエラーメッセージを出すので,
Version of PDF file (1.4) is newer than version limit specification. Can't handle file type for file named average.pdf
ebb のソースを弄ってもよいけど R による ebb を書いて見る。ついでに,png と jpg にも対応させる
ebb <- function(fn, verbose=TRUE) # .bb を作りたいファイルを fn に指定 { getSizePng <- function(fn) { w.h <- NA input <- file(fn, open="rb") pass <- readBin(input, raw(), 16) if (all(pass[1:4] == c("89", "50", "4e", "47"))) { w.h <- readBin(input, integer(), 2, size=4, endian="big") } close(input) return(w.h) } getSizeJpeg <- function(fn) { h.w <- NA input <- file(fn, open="rb") SOI <- readBin(input, raw(), 2) # ff d8 if (all(SOI==c("ff", "d8"))) { repeat { SOF0 <- readBin(input, raw(), 2) length <- readBin(input, integer(), size=2, endian="big") if (SOF0[1] == "ff" && ("c0" <= SOF0[2] && SOF0[2] <= "c3")) { accuracy <- readBin(input, integer(), size=1) h.w <- readBin(input, integer(), 2, size=2, endian="big") break } pass <- readBin(input, raw(), length-2) } } close(input) return(h.w[2:1]) } getSizePdf <- function(fn) { x <- readLines(fn) suppressWarnings(line.no <- grep("MediaBox", x)) if (length(line.no) > 0) { for (i in line.no) { bb <- x[i] if (!grepl("/MediaBox *\\[", bb)) { bb <- paste(bb, x[i+1]) } bb <- gsub("\\[", " ", bb) bb <- gsub("\\]", " ", bb) bb <- unlist(strsplit(bb, " +")) j <- grep("MediaBox", bb) w.h <- as.integer(bb[j+3:4]) return(w.h) } } stop(paste(fn, "のファイルのサイズは,わかんね〜な。")) } ###################################### if (file.exists(fn) == FALSE) { stop(paste(fn, "ってのは,見あたんね〜な。")) } file.bb <- sub(".(pdf|png|jpe*g)$", ".bb", fn, ignore.case=TRUE) if (file.exists(file.bb) == FALSE || file.info(file.bb)$mtime < file.info(fn)$mtime) { # 対象ファイルとその .bb ファイルの更新日時をみて必要なら作成 if (grepl(".pdf$", fn, ignore.case=TRUE)) { wh <- getSizePdf(fn) } else if (grepl(".png$", fn, ignore.case=TRUE)) { wh <- getSizePng(fn) } else if (grep(".jpe*g$", fn, ignore.case=TRUE)) { wh <- getSizeJpeg(fn) } if (verbose) cat(fn, ": ", wh, ", ", file.bb, "\n") writeLines(sprintf("%%%%Title: ./%s\n%%%%Creator: Rebb Version 0.0.1\n%%%%BoundingBox: 0 0 %d %d\n%%%%CreationDate: %s\n", fn, wh[1], wh[2], date()), file.bb) } } # シュガーコート ebbAll <- function(pattern="(.pdf|.png|.jpe*g)", ignore.case=TRUE, verbose=TRUE, ...) { invisible(sapply(list.files(pattern=pattern, ignore.case=ignore.case), ebb, verbose=verbose)) } # 使用法(作業ディレクトリ中のすべての pdf, png, jpg ファイルの .bb を作る) ebbAll(verbose=FALSE)