From: Don Armstrong Date: Fri, 1 Jul 2016 18:36:02 +0000 (-0500) Subject: add start of CairoHacks package X-Git-Url: https://git.donarmstrong.com/?p=r%2FCairoHacks.git;a=commitdiff_plain;h=ab965e02baa9042e42859e4af9682bf277407e2a add start of CairoHacks package --- ab965e02baa9042e42859e4af9682bf277407e2a diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..48e7bad --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,20 @@ +Package: CairoHacks +Type: Package +Title: Various hacks for Cairo devices including PDF bookmarks and raster plots in PDFs +Version: 1.0 +Date: 2016-06-20 +Authors@R: person("Don","Armstrong",email="don@donarmstrong.com",role=c("aut","cre")) +Maintainer: Don Armstrong +Depends: Cairo, grid +Description: Routines which enable the addition of PDF bookmarks + (table of contents) to PDFs and methods to plot raster plots in the + middle of PDF plots. + . + Bookmarks enable the easy browsing of PDFs by table of contents/index + using pdftk. + . + Raster plots enable the inclusion of plots with millions of points or + lines in a vector format (such as a PDF) without making the PDF file + megabytes in size, while still allowing other plot components to be + presented in their original vector format. +License: GPL (>=3) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b119c24 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +#!/usr/bin/make -f + +R ?= R +ROPTS=-q --no-save --no-restore-data + +update_docs: + $(R) $(ROPTS) -e "devtools::document()" + +check: + $(R) $(ROPTS) -e "devtools::check(manual=TRUE)" diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..4132a5e --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,9 @@ +# Generated by roxygen2 (4.1.1): do not edit by hand + +S3method("+",CairoHacks_bookmark) +export(make.pdf.bookmark) +export(start_rasterplot) +export(stop_rasterplot) +export(write.pdf.bookmarks) +import(Cairo) +import(grid) diff --git a/R/CairoHacks.R b/R/CairoHacks.R new file mode 100644 index 0000000..ea84fbe --- /dev/null +++ b/R/CairoHacks.R @@ -0,0 +1,25 @@ +#' CairoHacks: Various hacks for Cairo devices including PDF bookmarks and raster plots in PDFs +#' +#' CairoHacks contains routines to allow you to include PDF bookmarks +#' and raster plots inside of your PDFs. +#' +#' @section Bookmarks: +#' +#' Bookmarks enable the easy browsing of PDFs by table of contents/index +#' using pdftk. +#' +#' @seealso make.pdf.bookmark, write.pdf.bookmark +#' +#' @section Raster Plots: +#' +#' Raster plots enable the inclusion of plots with millions of points or +#' lines in a vector format (such as a PDF) without making the PDF file +#' megabytes in size, while still allowing other plot components to be +#' presented in their original vector format. +#' +#' @seealso start_rasterplot, stop_rasterplot +#' +#' @docType package +#' @name CairoHacks +#' @author Don Armstrong +NULL diff --git a/R/bookmarks.R b/R/bookmarks.R new file mode 100644 index 0000000..4ced5a3 --- /dev/null +++ b/R/bookmarks.R @@ -0,0 +1,99 @@ +CairoHacks.env <- new.env() +CairoHacks.env$device_set_up <- FALSE +CairoHacks.env$current_page <- 0 + +##' Make a bookmark for a PDF for later saving to the pdf with +##' \code{write.pdf.bookmarks} +##' +##' +##' @title make.bookmark +##' @param text Text of bookmark to create +##' @param level Optional bookmark level which defaults to 1. This +##' enables you to have headings and sub-headings and so forth, simply +##' by increasing the number passed. +##' @param page Optional page number to write the bookmark to. If you +##' are using a Cairo device, this is automatically set for you to be +##' the page which you are currently writing to. +##' @return list of bookmarks to be passed to write.bookmarks or +##' further calls to save.bookmark +##' @author Don Armstrong +##' @export +##' @examples +##' CairoPDF(file="example.pdf",onefile=TRUE) +##' plot(y~x,data.frame(x=1:5,y=1:5)) +##' bookmarks <- make.pdf.bookmark("First plot") +##' plot(y~x,data.frame(x=1:5,y=1:5)) +##' bookmarks <- bookmarks + make.pdf.bookmark("Second plot") +##' dev.off() +##' write.pdf.bookmarks(file="example.pdf",bookmarks) +make.pdf.bookmark <- function(text,level=1,page=NULL) { + if (!CairoHacks.env$device_set_up) { + Cairo.onSave(device = dev.cur(), + onSave=function(device,page){ + ch <- getNamespace("CairoHacks") + print(ls(envir=ch)) + assign("current_page", + page, + envir=ch[["CairoHacks.env"]]) + }) + CairoHacks.env$device_set_up <- TRUE + } + if (missing(page)|| is.null(page)) { + page <- CairoHacks.env$current_page + } + p <- structure(list( + bookmarks=list( + list(text=text, + level=level, + page=page)) + ), class = c("CairoHacks_bookmark")) + return(p) +} +##' Add additional bookmarks to a bookmark +##' +##' Given a bookmarks object created with make.pdf.bookmark, add more +##' bookmarks to it. +##' @title + CairoHacks_bookmark +##' @param b1 An object of class CairoHacks_bookmark. +##' @param b2 An object of class CairoHacks_bookmark +##' @export +##' @method + CairoHacks_bookmark +##' @author Don Armstrong +"+.CairoHacks_bookmark" <- function(b1,b2) { + b1[["bookmarks"]] <- + c(b1[["bookmarks"]], + b2[["bookmarks"]]) + b1 +} +##' Write saved bookmarks to the PDF file which was generated +##' +##' Given a set of bookmarks generated with make.pdf.bookmark, write +##' them out to a PDF file using pdftk. +##' @title write.pdf.bookmarks +##' @param file file name of pdf which was saved to disk +##' @param bookmarks list of bookmarks +##' @return list of bookmarks +##' @author Don Armstrong +##' @export +write.pdf.bookmarks <- function(file,bookmarks) { + pdf.bookmarks <- "" + print(bookmarks[["bookmarks"]]) + for (bookmark in 1:length(bookmarks[["bookmarks"]])) { + pdf.bookmarks <- + paste0(pdf.bookmarks, + "BookmarkBegin\n", + "BookmarkTitle: ",bookmarks[["bookmarks"]][[bookmark]][["text"]],"\n", + "BookmarkLevel: ",bookmarks[["bookmarks"]][[bookmark]][["level"]],"\n", + "BookmarkPageNumber: ",bookmarks[["bookmarks"]][[bookmark]][["page"]],"\n") + } + temp.pdf <- tempfile(pattern=basename(file)) + temp.pdf.info <- tempfile(pattern=paste0(basename(file),"info_utf8")) + cat(file=temp.pdf.info,pdf.bookmarks) + system2("pdftk",c(file,'update_info_utf8',temp.pdf.info,'output',temp.pdf)) + if (file.exists(temp.pdf)) { + file.rename(temp.pdf,file) + } else { + stop("unable to properly create bookmarks") + } + invisible(bookmarks) +} diff --git a/R/raster_plots.R b/R/raster_plots.R new file mode 100644 index 0000000..2e831a9 --- /dev/null +++ b/R/raster_plots.R @@ -0,0 +1,74 @@ +##' Start a raster plot with indicated width or height in pixels +##' +##' This creates a Cairo device with output to /dev/null of width or +##' height given (defaulting to a width of 1024) +##' @title start_rasterplot +##' @param width Width in pixels of raster image +##' @param height Height in pixels of raster image. In general only +##' one of \code{width} or \code{height} should be provided. +##' @return NULL +##' @author Don Armstrong +##' @export +##' @import Cairo grid +##' @examples +##' \dontrun{ +##' ### plot a raster plot in a PDF +##' pdf() +##' start_rasterplot() +##' print(xyplot(y~x, +##' data=data.frame(y=rnorm(1E8),x=rnorm(1E8)))) +##' stop_rasterplot() +##' dev.off() +##' } +##' +##' ### plot a raster plot using grid.raster +##' start_rasterplot(width=100) +##' print(plot(y~x, +##' data=data.frame(y=rnorm(1E4), +##' x=rnorm(1E4)))) +##' raster.image <- stop_rasterplot(plot=FALSE) +##' grid.raster(raster.image) +start_rasterplot <- function(width=NULL,height=NULL) { + x.y.ratio <- grid::convertX(grid::unit(1,"npc"),"mm",valueOnly=TRUE)/ + grid::convertY(grid::unit(1,"npc"),"mm",valueOnly=TRUE) + width.points <- as.numeric(grid::convertX(grid::unit(1,"npc"),"points")) + dpi <- as.numeric(grid::convertX(grid::unit(1,"inch"),"point")) + if (is.null(width) && is.null(height)) { + width <- 1024 + } + if (is.null(width)) { + width <- height*x.y.ratio + } + else if (is.null(height)) { + height <- width/x.y.ratio + } else { + if (height != width/x.y.ratio) { + warning(paste0("You've provided both width and height, ", + "but they do not match the actual ratio ", + "of the plot. Consider only providing one ", + "if the results look bad.")) + } + } + + Cairo::Cairo(width=width,height=height,dpi=width/width.points*dpi,file="/dev/null") + NULL +} +##' Stops a raster plot and returns the results and optionally plots them +##' +##' This stops a raster plot created with start_rasterplot and plots +##' the result. +##' @title stop_rasterplot +##' @param plot Boolean indicating whether the captured raster image +##' should be plotted or not +##' @return raster image suitable for plotting with \code{grid.raster()} +##' @author Don Armstrong +##' @export +##' @seealso start_rasterplot +stop_rasterplot <- function(plot=TRUE) { + raster.image <- dev.capture(native=TRUE) + dev.off() + if (plot) { + grid::grid.raster(raster.image,width=grid::unit(1,"npc"),height=grid::unit(1,"npc")) + } + invisible(raster.image) +} diff --git a/man/CairoHacks.Rd b/man/CairoHacks.Rd new file mode 100644 index 0000000..aa944a6 --- /dev/null +++ b/man/CairoHacks.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/CairoHacks.R +\docType{package} +\name{CairoHacks} +\alias{CairoHacks} +\alias{CairoHacks-package} +\title{CairoHacks: Various hacks for Cairo devices including PDF bookmarks and raster plots in PDFs} +\description{ +CairoHacks contains routines to allow you to include PDF bookmarks +and raster plots inside of your PDFs. +} +\section{Bookmarks}{ + + +Bookmarks enable the easy browsing of PDFs by table of contents/index +using pdftk. +} + +\section{Raster Plots}{ + + +Raster plots enable the inclusion of plots with millions of points or +lines in a vector format (such as a PDF) without making the PDF file +megabytes in size, while still allowing other plot components to be +presented in their original vector format. +} +\author{ +Don Armstrong +} +\seealso{ +make.pdf.bookmark, write.pdf.bookmark + +start_rasterplot, stop_rasterplot +} + diff --git a/man/make.pdf.bookmark.Rd b/man/make.pdf.bookmark.Rd new file mode 100644 index 0000000..0621ab6 --- /dev/null +++ b/man/make.pdf.bookmark.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/bookmarks.R +\name{make.pdf.bookmark} +\alias{make.pdf.bookmark} +\title{make.bookmark} +\usage{ +make.pdf.bookmark(text, level = 1, page = NULL) +} +\arguments{ +\item{text}{Text of bookmark to create} + +\item{level}{Optional bookmark level which defaults to 1. This +enables you to have headings and sub-headings and so forth, simply +by increasing the number passed.} + +\item{page}{Optional page number to write the bookmark to. If you +are using a Cairo device, this is automatically set for you to be +the page which you are currently writing to.} +} +\value{ +list of bookmarks to be passed to write.bookmarks or +further calls to save.bookmark +} +\description{ +Make a bookmark for a PDF for later saving to the pdf with +\code{write.pdf.bookmarks} +} +\examples{ +CairoPDF(file="example.pdf",onefile=TRUE) +plot(y~x,data.frame(x=1:5,y=1:5)) +bookmarks <- make.pdf.bookmark("First plot") +plot(y~x,data.frame(x=1:5,y=1:5)) +bookmarks <- bookmarks + make.pdf.bookmark("Second plot") +dev.off() +write.pdf.bookmarks(file="example.pdf",bookmarks) +} +\author{ +Don Armstrong +} + diff --git a/man/plus-.CairoHacks_bookmark.Rd b/man/plus-.CairoHacks_bookmark.Rd new file mode 100644 index 0000000..22920e1 --- /dev/null +++ b/man/plus-.CairoHacks_bookmark.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/bookmarks.R +\name{+.CairoHacks_bookmark} +\alias{+.CairoHacks_bookmark} +\title{+ CairoHacks_bookmark} +\usage{ +\method{+}{CairoHacks_bookmark}(b1, b2) +} +\arguments{ +\item{b1}{An object of class CairoHacks_bookmark.} + +\item{b2}{An object of class CairoHacks_bookmark} +} +\description{ +Add additional bookmarks to a bookmark +} +\details{ +Given a bookmarks object created with make.pdf.bookmark, add more +bookmarks to it. +} +\author{ +Don Armstrong +} + diff --git a/man/start_rasterplot.Rd b/man/start_rasterplot.Rd new file mode 100644 index 0000000..b14e5a1 --- /dev/null +++ b/man/start_rasterplot.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/raster_plots.R +\name{start_rasterplot} +\alias{start_rasterplot} +\title{start_rasterplot} +\usage{ +start_rasterplot(width = NULL, height = NULL) +} +\arguments{ +\item{width}{Width in pixels of raster image} + +\item{height}{Height in pixels of raster image. In general only +one of \code{width} or \code{height} should be provided.} +} +\description{ +Start a raster plot with indicated width or height in pixels +} +\details{ +This creates a Cairo device with output to /dev/null of width or +height given (defaulting to a width of 1024) +} +\examples{ +\dontrun{ +### plot a raster plot in a PDF +pdf() +start_rasterplot() +print(xyplot(y~x, + data=data.frame(y=rnorm(1E8),x=rnorm(1E8)))) +stop_rasterplot() +dev.off() +} + +### plot a raster plot using grid.raster +start_rasterplot(width=100) +print(plot(y~x, + data=data.frame(y=rnorm(1E4), + x=rnorm(1E4)))) +raster.image <- stop_rasterplot(plot=FALSE) +grid.raster(raster.image) +} +\author{ +Don Armstrong +} + diff --git a/man/stop_rasterplot.Rd b/man/stop_rasterplot.Rd new file mode 100644 index 0000000..1cee08b --- /dev/null +++ b/man/stop_rasterplot.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/raster_plots.R +\name{stop_rasterplot} +\alias{stop_rasterplot} +\title{stop_rasterplot} +\usage{ +stop_rasterplot(plot = TRUE) +} +\arguments{ +\item{plot}{Boolean indicating whether the captured raster image +should be plotted or not} +} +\value{ +raster image suitable for plotting with \code{grid.raster()} +} +\description{ +Stops a raster plot and returns the results and optionally plots them +} +\details{ +This stops a raster plot created with start_rasterplot and plots +the result. +} +\author{ +Don Armstrong +} +\seealso{ +start_rasterplot +} + diff --git a/man/write.pdf.bookmarks.Rd b/man/write.pdf.bookmarks.Rd new file mode 100644 index 0000000..69367f8 --- /dev/null +++ b/man/write.pdf.bookmarks.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/bookmarks.R +\name{write.pdf.bookmarks} +\alias{write.pdf.bookmarks} +\title{write.pdf.bookmarks} +\usage{ +write.pdf.bookmarks(file, bookmarks) +} +\arguments{ +\item{file}{file name of pdf which was saved to disk} + +\item{bookmarks}{list of bookmarks} +} +\value{ +list of bookmarks +} +\description{ +Write saved bookmarks to the PDF file which was generated +} +\details{ +Given a set of bookmarks generated with make.pdf.bookmark, write +them out to a PDF file using pdftk. +} +\author{ +Don Armstrong +} +