grImport2/0000755000176200001440000000000013567034712012147 5ustar liggesusersgrImport2/NAMESPACE0000654000176200001440000000305013560126770013364 0ustar liggesusersimport(grid) import(XML) import(methods) importFrom(grDevices, pdf, dev.off, rgb) importFrom(base64enc, base64decode) importFrom(png, readPNG) importFrom(jpeg, readJPEG) exportClasses("Picture") exportClasses("PictureClipPath") exportClasses("PictureContent") exportClasses("PictureDefinitions") exportClasses("PictureFeColorMatrix") exportClasses("PictureFilter") exportClasses("PictureGradientStop") exportClasses("PictureGroup") exportClasses("PictureImage") exportClasses("PictureLinearGradient") exportClasses("PictureMask") exportClasses("PicturePath") exportClasses("PathData") exportClasses("PathSegment") exportClasses("PathMoveTo") exportClasses("PathLineTo") exportClasses("PathCurveTo") exportClasses("PathClosePath") exportClasses("PicturePattern") exportClasses("PicturePath") exportClasses("PictureRadialGradient") exportClasses("PictureRect") exportClasses("PictureSummary") exportClasses("PictureSymbol") exportMethods("[") exportMethods("[[") exportMethods("applyTransform") exportMethods("grobify") exportMethods("getDef") exportMethods("setDef") # Just S4 wrappers #exportClasses("gpar") #exportClasses("nativeRaster") # Path wrappers export(moveTo, lineTo, curveTo, closePath) export(readPicture) export(grid.picture) export(pictureGrob) export(grid.symbols) export(symbolsGrob) S3method("makeContent", "PictureGrob") S3method("makeContext", "picRect") S3method("makeContent", "picRect") S3method("makeContent", "picPolyline") S3method("makeContent", "picPath") S3method("makeContext", "picComplexPath") grImport2/man/0000755000176200001440000000000012631661433012717 5ustar liggesusersgrImport2/man/PictureRect-class.Rd0000654000176200001440000000537412631661433016554 0ustar liggesusers\name{PictureRect-class} \docType{class} \alias{PictureRect-class} \alias{applyTransform,PictureRect,matrix-method} \alias{grobify,PictureRect-method} \title{Class \code{"PictureRect"}} \description{ A description of a rectangle. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. A vector of length one representing the x-location of the top-left corner of the rectangle. } \item{\code{y}:}{ Object of class \code{"numeric"}. A vector of length one representing the y-location of the top-left corner of the rectangle. } \item{\code{width}:}{ Object of class \code{"numeric"}. A vector of length one representing the width of the rectangle. } \item{\code{height}:}{ Object of class \code{"numeric"}. A vector of length one representing the height of the rectangle. } \item{\code{angle}:}{ Object of class \code{"numeric"}. A vector of length one representing the angle applied to the image. Corresponds to grid's viewport angles. } \item{\code{gp}:}{ Object of class \code{"gpar"}. A grid \code{gpar} object. } \item{\code{bbox}:}{ Object of class \code{"numeric"}. Represented as \code{[xmin, xmax, ymin, ymax]}. The bounding box of the rectangle. Used for features such as clipping. } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PictureRect", tm = "matrix")}: transforms the locations described by the rectangle object by a 3x3 transformation matrix and returns a \code{"PictureRect"} object with the transformed locations. } \item{grobify}{\code{signature(object = "PictureRect")}: converts the object into a grid rectangle grob. While not intended to be used directly, this method contains three arguments: \describe{ \item{\code{defs}}{ An object of class \code{"PictureDefinitions"} that contains definitions of graphical content, primarily for use with the gridSVG package. } \item{\code{gpFUN}}{ This argument takes a function that should expect to take a single \code{gpar} object and return a modified \code{gpar} object. By default, the value of this argument is the identity function. } \item{\code{ext}}{ A character vector. See \code{\link{grid.picture}} for more information on what this extension selection parameter means, in addition to the valid values this argument takes. } } } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PicturePath}}. } grImport2/man/applyTransform-gpar.Rd0000654000176200001440000000077212207234375017165 0ustar liggesusers\name{applyTransform-gpar} \docType{methods} \alias{applyTransform,gpar,matrix-method} \title{ Transform a grid \code{gpar} object } \description{ Transform a grid \code{gpar} object. } \section{Methods}{ \describe{ \item{ \code{signature(object = "gpar", tm = "matrix")}}{ Transforms the \code{"lwd"} and \code{"lty"} components of a \code{gpar} object (if present) by a 3x3 transformation matrix and returns the modified gpar object. } } } \author{ Simon Potter } grImport2/man/grobify.Rd0000654000176200001440000000432212207234375014651 0ustar liggesusers\name{grobify} \alias{grobify} \title{ Convert a Picture Object into a grid grob } \description{ Converts \code{"Picture"} objects and pieces of a picture (i.e. objects inheriting from \code{"PictureContent"} objects) into grid grobs. } \usage{ grobify(object, ...) } \arguments{ \item{object}{ An object that contains \code{grobify} methods. Typically a \code{"Picture"} object. } \item{\dots}{ Further arguments to specific \code{grobify} methods. } } \details{ Although not required by some grobify methods, there are further arguments that may be used, which will be described here. \describe{ \item{\code{defs}}{ This argument should take a \code{"PictureDefinitions"} object that contains definitions of referenced content. This is only useful when the \code{gridSVG} is set to \code{TRUE}. } \item{\code{clip}}{ This argument is supplied in the form of a character vector. It usually only applies when grobifying a \code{"PictureGroup"} object. There are three possible values for \code{clip}: \describe{ \item{\code{none}}{ No clipping will be applied to the object. } \item{\code{bbox}}{ The clipping will be applied to the rectangular region that bounds the clipping path's content. This argument is particularly useful as R graphics can only use rectangular clipping regions. If we want more complex clipping regions, the value of \code{gridSVG} must be used instead. } \item{\code{gridSVG}}{ When this value is set, we are no longer restricted to clipping to rectangular regions, and many images will require it to be set to display correctly. This argument requires the gridSVG package to be installed. } } } \item{\code{gridSVG}}{ This is a logical value that, when \code{TRUE}, allows graphical features to be drawn that are not possible in R graphics. This requires the gridSVG package. When this argument is \code{TRUE} we can correctly import and render patterns, masks, filters and gradients. } } } \value{ A grid grob. } \author{ Simon Potter } grImport2/man/PictureContent-class.Rd0000654000176200001440000000055212207234375017262 0ustar liggesusers\name{PictureContent-class} \docType{class} \alias{PictureContent-class} \title{Class \code{"PictureContent"}} \description{ A virtual class that is used for verifying validity of \code{"Picture"} objects. } \author{ Simon Potter } \seealso{ \code{\linkS4class{PicturePath}}, \code{\linkS4class{PictureRect}}, \code{\linkS4class{PictureGroup}}, etc. } grImport2/man/PicturePattern-class.Rd0000654000176200001440000000452512631661433017271 0ustar liggesusers\name{PicturePattern-class} \docType{class} \alias{PicturePattern-class} \alias{applyTransform,PicturePattern,matrix-method} \alias{grobify,PicturePattern-method} \title{Class \code{"PicturePattern"}} \description{ A description of a pattern to be referenced (and used) by graphical content. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. A vector of length one representing the x-location of the top-left corner of the pattern. } \item{\code{y}:}{ Object of class \code{"numeric"}. A vector of length one representing the y-location of the top-left corner of the pattern. } \item{\code{width}:}{ Object of class \code{"numeric"}. A vector of length one representing the width of the pattern. } \item{\code{height}:}{ Object of class \code{"numeric"}. A vector of length one representing the height of the pattern. } \item{\code{angle}:}{ Object of class \code{"numeric"}. A vector of length one representing the angle applied to the image. Corresponds to grid's viewport angles. } \item{\code{definition}:}{ Object of class \code{"list"}. A list of \code{"PictureContent"} objects that define the content of the pattern "tile". } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PicturePattern", tm = "matrix")}: transforms the locations described by the pattern object by a 3x3 transformation matrix and returns a \code{"PicturePattern"} object with the transformed locations. } \item{grobify}{\code{signature(object = "PicturePattern")}: convert the pattern description into a gridSVG pattern object. Useful only in conjunction with the gridSVG package. The pattern object will store the definition of the pattern (almost certainly a raster of some sort) as a grob too. While not intended to be used directly, this method contains a single optional argument. This argument is \code{ext}, a character vector. See \code{\link{grid.picture}} for more information on what this extension selection parameter means, in addition to the valid values this argument takes. } } } \author{ Simon Potter } grImport2/man/PictureSummary-class.Rd0000654000176200001440000000076212207234375017310 0ustar liggesusers\name{PictureSummary-class} \docType{class} \alias{PictureSummary-class} \title{Class "PictureSummary" } \description{Summary information about a picture regarding the scales of its bounding box. } \section{Slots}{ \describe{ \item{\code{xscale}:}{Object of class \code{"numeric"} range of x-values in picture.} \item{\code{yscale}:}{Object of class \code{"numeric"} range of y-values in picture.} } } \author{ Simon Potter } \seealso{ \code{\link{Picture-class}} } \keyword{classes} grImport2/man/PictureImage-class.Rd0000654000176200001440000000535212631661433016675 0ustar liggesusers\name{PictureImage-class} \docType{class} \alias{PictureImage-class} \alias{applyTransform,PictureImage,matrix-method} \alias{grobify,PictureImage-method} \title{Class \code{"PictureImage"}} \description{ A description of a raster image. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. A vector of length one representing the x-location of the top-left corner of the image. } \item{\code{y}:}{ Object of class \code{"numeric"}. A vector of length one representing the y-location of the top-left corner of the image. } \item{\code{width}:}{ Object of class \code{"numeric"}. A vector of length one representing the width of the image. } \item{\code{height}:}{ Object of class \code{"numeric"}. A vector of length one representing the height of the image. } \item{\code{image}:}{ Object of class \code{"nativeRaster"}. A description of the raster image as an array of integers representing pixel colours. Not intended to be created directly, but as a result of calling the \code{jpeg} and \code{png} packages \code{read*()} functions. } \item{\code{angle}:}{ Object of class \code{"numeric"}. A vector of length one representing the angle applied to the image. Corresponds to grid's viewport angles. } \item{\code{maskRef}:}{ Object of class \code{"ANY"}. A character reference to an object that will mask this image. Not intended to be used directly (so can be \code{NULL}. } \item{\code{bbox}:}{ Object of class \code{"numeric"}. Represented as \code{[xmin, xmax, ymin, ymax]}. The bounding box of the image. Used for features such as clipping. } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PictureImage", tm = "matrix")}: transforms each location described by the image by a 3x3 transformation matrix and returns a new \code{"PictureImage"} object with the newly transformed locations. } \item{grobify}{ \code{signature(object = "PictureImage")}: converts the image description into a grid raster grob that represents the image. Typically used in conjunction with a pattern. While not intended to be used directly, this function contains a single optional argument, \code{ext}, which is a character vector. See \code{\link{grid.picture}} for more information on what this extension selection parameter means, in addition to the valid values this argument takes. } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PictureRect}}. } grImport2/man/grid.symbols.Rd0000654000176200001440000000505412231346762015630 0ustar liggesusers\name{grid.symbols} \alias{symbolsGrob} \alias{grid.symbols} \title{ Draw a Picture Object as Data Symbols } \description{ These functions take a \code{"Picture"} object and either draw the picture at several locations or create a grid graphical object representing the picture (drawn at several locations). } \usage{ symbolsGrob(picture, x = stats::runif(10), y = stats::runif(10), size = unit(1, "char"), default.units = "native", gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), prefix = NULL, ..., name = NULL) grid.symbols(...) } \arguments{ \item{picture}{ A \code{"Picture"} object. } \item{x}{ A numeric vector or unit object specifying x-locations. } \item{y}{ A numeric vector or unit object specifying y-locations. } \item{size}{ A numeric vector or unit object specifying symbol sizes. } \item{default.units}{ A string indicating the default units to use if \code{x}, \code{y}, \code{width}, or \code{height} are only given as numeric vectors. } \item{gpFUN}{ A function that takes a grid \code{gpar} object and returns a (possibly modified) \code{gpar} object. } \item{ext}{ A character vector. Selects from one of three possible extensions for drawing imported pictures. \code{"none"} means that no clipping will be applied to the imported picture. \code{"clipbbox"} means that clipping will be applied, but only to the bounding boxes of any imported clipping paths. \code{"gridSVG"} means that gridSVG will be used when drawing the \code{"Picture"} object, which enables the use of complex clipping paths, gradients, patterns, etc. to be rendered from an imported picture. } \item{prefix}{ A character string. A prefix to add to referenced gridSVG content (e.g. pattern fills). Only used when \code{gridSVG} is \code{TRUE}. The reference label must be a unique reference label, otherwise an error will result. This can be checked by calling gridSVG's \code{listSVGDefinitions()}. When this parameter is \code{NULL}, a prefix will automatically be generated but this is not guaranteed to be unique. } \item{\dots}{ For \code{grid.symbols()}, arguments to be passed onto \code{symbolsGrob()}. For \code{symbolsGrob()}, additional parameters to be passed onto the \code{picture}'s \code{grobify} method. } \item{name}{ A character identifier. } } \value{ A grid grob. } \author{ Simon Potter } \seealso{ \code{\link{grid.picture}} } grImport2/man/PictureFilter-class.Rd0000654000176200001440000000321212207234375017071 0ustar liggesusers\name{PictureFilter-class} \docType{class} \alias{PictureFilter-class} \alias{grobify,PictureFilter-method} \title{Class \code{"PictureFilter"}} \description{ A description of a filter effect. To be used in conjunction with the gridSVG package. } \section{Slots}{ \describe{ \item{\code{filterUnits}:}{ Object of class \code{"character"}. The units that the filter effect should be positioned against. This should always be \code{"bbox"}. } \item{\code{x}:}{ Object of class \code{"numeric"}. A vector of length one representing the x-location of the bottom-left corner of the filter effect region. } \item{\code{y}:}{ Object of class \code{"numeric"}. A vector of length one representing the y-location of the bottom-left corner of the filter effect region. } \item{\code{width}:}{ Object of class \code{"numeric"}. A vector of length one representing the width of the filter effect region. } \item{\code{height}:}{ Object of class \code{"numeric"}. A vector of length one representing the height of the filter effect region. } \item{\code{content}:}{ Object of class \code{"PictureFeColorMatrix"}. A description of the colour transformation matrix applied to a filter target. } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{grobify}{ \code{signature(object = "PictureFilter")}: Creates a filter effect object for use with the gridSVG package. } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PictureFeColorMatrix}} } grImport2/man/PictureGroup-class.Rd0000654000176200001440000000676612631661433016761 0ustar liggesusers\name{PictureGroup-class} \docType{class} \alias{PictureGroup-class} \alias{[,PictureGroup-method} \alias{[[,PictureGroup-method} \alias{applyTransform,PictureGroup,matrix-method} \alias{grobify,PictureGroup-method} \title{Class \code{"PictureGroup"}} \description{ A grouped collection of picture pieces. } \section{Slots}{ \describe{ \item{\code{content}:}{ Object of class \code{"list"} that is a list of objects of class \code{"PictureContent"}. } \item{\code{clip}:}{ Object of class \code{"ANY"}. Either \code{NULL} or an object of class \code{"PictureClipPath"}. } \item{\code{filterRef}:}{ Object of class \code{"ANY"}. A character reference to an object that will apply a filter effect to this group. Not intended to be used directly (so can be \code{NULL}. } \item{\code{maskRef}:}{ Object of class \code{"ANY"}. A character reference to an object that will mask this group. Not intended to be used directly (so can be \code{NULL}. } \item{\code{gp}:}{ Object of class \code{"gpar"}. A grid \code{gpar} object to apply to the group. } } } \section{Extends}{ Class \code{"\linkS4class{PictureContent}"}, directly. } \section{Methods}{ \describe{ \item{[}{ \code{signature(x = "PictureGroup")}: subset the content of the group to produce a new picture. } \item{[[}{ \code{signature(x = "PictureGroup")}: extract a single piece of a picture group. Each piece will be an object of class \code{"PictureContent"}. } \item{applyTransform}{ \code{signature(object = "PictureGroup", tm = "matrix")}: transforms the locations described by contents of the group object by a 3x3 transformation matrix and returns a \code{"PictureGroup"} object whose children have had locations transformed by the matrix. } \item{grobify}{ \code{signature(object = "PictureGroup")}: convert to a grid grob (for use as a one-off image) for drawing. This method is typically not called directly but can take three additional arguments. \describe{ \item{\code{defs}}{ This argument takes an object of class \code{"PictureDefinitions"}. This object allows us to make use of referenced content features in the gridSVG package. } \item{\code{gpFUN}}{ This arugment takes a function that modifies a \code{gpar} object. The function should take a single argument that is a \code{gpar} object, modify that \code{gpar} object, and then return it. By default this argument is assigned the value of the identity function. } \item{\code{ext}}{ A character vector. This argument can partially match to one of \code{off}, \code{clipbbox}, or \code{gridSVG}. When \code{off}, no clipping is applied to the group. When \code{clipbbox}, the contents of the group will be clipped to the bounding box of the clipping definition. When \code{gridSVG}, the contents of the group will be clipped to the non-zero region defined by the clipping definition, in addition to using gridSVG features (i.e. gradients, filters), when required. \code{bbox} is restricted to rectangular clipping regions, while \code{gridSVG} has no such restriction and can clip to any arbitrary region. } } } } } \author{ Simon Potter } \keyword{classes} grImport2/man/paths.Rd0000654000176200001440000000216412207234375014331 0ustar liggesusers\name{Path Segments} \alias{moveTo} \alias{lineTo} \alias{curveTo} \alias{closePath} \title{ Convenience Functions for Path Segments } \description{ These functions are convenience constructors for path segment objects of classes \code{"PathMoveTo"}, \code{"PathLineTo"}, \code{"PathCurveTo"} and \code{"PathClosePath"}. } \usage{ moveTo(x, y) lineTo(x, y) curveTo(x, y) closePath(x, y) } \arguments{ \item{x}{ A numeric vector representing x-locations. } \item{y}{ A numeric vector representing y-locations. } } \details{ For \code{x} and \code{y}, they should each be of length one so that they represent a single point location except in the case of \code{curveTo}. In the case of \code{curveTo}, it expects \code{x} and \code{y} vectors of length four, which represent control points in a cubic bezier curve. } \value{ For \code{moveTo}, an object of class \code{"PathMoveTo"}. For \code{lineTo}, an object of class \code{"PathLineTo"}. For \code{curveTo}, an object of class \code{"PathCurveTo"}. For \code{closePath}, an object of class \code{"PathClosePath"}. } \author{ Simon Potter } grImport2/man/PathMoveTo-class.Rd0000654000176200001440000000137612207234375016347 0ustar liggesusers\name{PathMoveTo-class} \docType{class} \alias{PathMoveTo-class} \title{Class \code{"PathMoveTo"}} \description{ A description of a path move to operator (\code{"M"} in SVG parlance) that is meant to be used as part of a path. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. The x-location that the path is going to move to. } \item{\code{y}:}{ Object of class \code{"numeric"}. The y-location that the path is going to move to. } } } \section{Extends}{ Class \code{\linkS4class{PathSegment}}, directly. } \author{ Simon Potter } \seealso{ \code{\linkS4class{PathData}}, \code{\linkS4class{PathClosePath}}, \code{\linkS4class{PathLineTo}}, \code{\linkS4class{PathCurveTo}}. } grImport2/man/PathClosePath-class.Rd0000654000176200001440000000141212207234375017007 0ustar liggesusers\name{PathClosePath-class} \docType{class} \alias{PathClosePath-class} \title{Class \code{"PathClosePath"}} \description{ A description of a path close path operator (\code{"Z"} in SVG parlance) that is meant to be used as part of a path. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. The x-location that the path is going to close to. } \item{\code{y}:}{ Object of class \code{"numeric"}. The y-location that the path is going to close to. } } } \section{Extends}{ Class \code{\linkS4class{PathSegment}}, directly. } \author{ Simon Potter } \seealso{ \code{\linkS4class{PathData}}, \code{\linkS4class{PathMoveTo}}, \code{\linkS4class{PathLineTo}}, \code{\linkS4class{PathCurveTo}}. } grImport2/man/PictureSymbol-class.Rd0000654000176200001440000000125412207234375017115 0ustar liggesusers\name{PictureSymbol-class} \docType{class} \alias{PictureSymbol-class} \title{Class \code{"PictureSymbol"}} \description{ A description of a symbol that is meant to be used (perhaps repeatedly) as part of a larger picture (as it does not directly draw anything itself). This object only has an effect while parsing a picture (via \code{\link{readPicture}}), so is not intended to be used directly by any user. } \section{Slots}{ \describe{ \item{\code{definition}:}{ Object of class \code{"list"}. A list of \code{"PictureContent"} objects. } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \author{ Simon Potter } grImport2/man/PicturePath-class.Rd0000654000176200001440000000457212231346762016553 0ustar liggesusers\name{PicturePath-class} \docType{class} \alias{PicturePath-class} \alias{applyTransform,PicturePath,matrix-method} \alias{grobify,PicturePath-method} \title{Class \code{"PicturePath"}} \description{ A description of a path. } \section{Slots}{ \describe{ \item{\code{d}:}{ Object of class \code{"PathData"}. A description of how the path draws and where it draws. } \item{\code{rule}:}{ Object of class \code{"character"}. A single element vector specifying the fill rule of the path. } \item{\code{gp}:}{ Object of class \code{"gpar"}. A grid \code{gpar} object that describes graphical parameters applied to the path. } \item{\code{bbox}:}{ Object of class \code{"numeric"}. The bounding box of the path. Represented as \code{[xmin, xmax, ymin, ymax]}. Used for features such as clipping. } } } \section{Extends}{ Class \code{linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PicturePath", tm = "matrix")}: transforms each location described by the path's data by a 3x3 transformation matrix and returns a new \code{"PicturePath"} object with the newly transformed locations. } \item{grobify}{ \code{signature(object = "PicturePath")}: converts the path description into a grid grob that represents the path. Although not expected to be called directly, this method contains three arguments. \describe{ \item{\code{defs}}{ An object of class \code{"PictureDefinitions"}. This object holds definitions of advanced graphical content, primarily for use with the gridSVG package. } \item{\code{gpFUN}}{ This argument expects to take a function that modifies a \code{gpar} object. This function should take a \code{gpar} object and return a modified \code{gpar} object. By default this argument is the identity function. } \item{\code{ext}}{ A character vector. See \code{\link{grid.picture}} for more information on what this extension selection parameter means, in addition to the valid values this argument takes. } } } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PictureRect}}, \code{\linkS4class{PathData}}. } grImport2/man/PictureFeColorMatrix-class.Rd0000654000176200001440000000165512207234375020373 0ustar liggesusers\name{PictureFeColorMatrix-class} \docType{class} \alias{PictureFeColorMatrix-class} \alias{grobify,PictureFeColorMatrix-method} \title{Class \code{"PictureFeColorMatrix"}} \description{ A description of a colour transformation matrix filter effect primitive. To be used in conjunction with the gridSVG package. } \section{Slots}{ \describe{ \item{\code{type}:}{Object of class \code{"character"} ~~ } \item{\code{input}:}{Object of class \code{"character"} ~~ } \item{\code{values}:}{Object of class \code{"matrix"} ~~ } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{grobify}{ \code{signature(object = "PictureFeColorMatrix")}: creates an \code{feColorMatrix} object to include in a filter effect object for use with the gridSVG package. } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PictureFilter}} } grImport2/man/PictureRadialGradient-class.Rd0000654000176200001440000000411412207234375020520 0ustar liggesusers\name{PictureRadialGradient-class} \docType{class} \alias{PictureRadialGradient-class} \alias{applyTransform,PictureRadialGradient,matrix-method} \alias{grobify,PictureRadialGradient-method} \title{Class "PictureRadialGradient" } \description{ A description of a radial gradient that is meant to be used as part of a larger picture (as it does not directly draw anything itself). This object will have no effect unless it is used in conjunction with the gridSVG package. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. The x-location of the radial gradient. } \item{\code{y}:}{ Object of class \code{"numeric"}. The y-location of the radial gradient. } \item{\code{r}:}{ Object of class \code{"numeric"}. The radius of the radial gradient. } \item{\code{fx}:}{ Object of class \code{"numeric"}. The x-location of the focal point of the radial gradient. } \item{\code{fy}:}{ Object of class \code{"numeric"}. The y-location of the focal point of the radial gradient. } \item{\code{spreadMethod}:}{ Object of class \code{"character"} that specifies what happens when a gradient ends within its bounds. Must be one of "pad", "reflect" or "repeat". See \code{"radialGradient"} in the gridSVG package for more information. } \item{\code{stops}:}{ Object of class \code{"list"} that is a list of objects of class \code{"PictureGradientStop"}. } } } \section{Extends}{ Class \code{"PictureContent"}. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PictureRadialGradient", tm = "matrix")}: transform the locations that represent the bounds and direction of the gradient by a 3x3 transformation matrix. } \item{grobify}{\code{signature(object = "PictureRadialGradient")}: convert to a gradient object for use with the gridSVG package. } } } \author{ Simon Potter } \seealso{ \code{\link{Picture-class}}, \code{\link{grid.picture}}. } \keyword{classes} grImport2/man/readPicture.Rd0000654000176200001440000000405413566620425015465 0ustar liggesusers\name{readPicture} \alias{readPicture} \title{ Import a Cairo SVG image } \description{ This function reads in an SVG image file and creates a \code{"Picture"} object. } \usage{ readPicture(file, warn = TRUE, initDefs = TRUE) } \arguments{ \item{file}{ The filename of a Cairo SVG image. } \item{warn}{ Logical. If \code{TRUE}, this will warn if \code{file} was not generated by Cairo graphics (see Details). } \item{initDefs}{ Logical. If \code{TRUE}, the global list of definitions (for things like masks, filters, gradient fills, ...) is initialised. } } \details{ This function is designed to read SVG files that have been generated by the Cairo graphics system. There are several ways to generate Cairo SVG files: The R SVG graphics device, provided by the \code{\link{svg}} function, produces Cairo SVG; the \pkg{grConvert} package (Linux-only) can convert PostScript, or PDF, or SVG files to Cairo SVG; and the \pkg{rsvg} package can convert many different graphics formats to Cairo SVG. It is very unlikely that an SVG file that was NOT generated by Cairo will import properly. This function may read the file without error, but the render (via \code{\link{grid.picture}}) is very unlikely to faithfully reproduce the original image. } \value{ An object of class \code{"Picture"}. } \references{ The Cairo graphics library, \url{https://cairographics.org/} } \author{ Simon Potter } \examples{ options(warn=1) ## NOT a Cairo SVG file badfile <- system.file("SVG", "lwd.svg", package="grImport2") ## A Cairo SVG file goodfile <- system.file("SVG", "lwd-rsvg.svg", package="grImport2") ## Warning because NOT a Cairo SVG file ## (and it will not render correctly) img <- readPicture(badfile) ## No warning ## (and it will render correctly) img <- readPicture(goodfile) if (require("rsvg")) { ## Generate a Cairo SVG file goodfile <- tempfile(fileext = ".svg") rsvg_svg(badfile, goodfile) ## No warning ## (and it will render correctly) img <- readPicture(goodfile) } options(warn=0) } grImport2/man/PathSegment-class.Rd0000654000176200001440000000215112207234375016530 0ustar liggesusers\name{PathSegment-class} \docType{class} \alias{PathSegment-class} \alias{applyTransform,PathSegment,matrix-method} \title{Class \code{"PathSegment"}} \description{ A segment of a path that is not intended to be used directly, merely as a convenience base class for path segment operators. } \section{Slots}{ \describe{ \item{\code{x}:}{Object of class \code{"numeric"}. An x-location.} \item{\code{y}:}{Object of class \code{"numeric"}. A y-location.} } } \section{Methods}{ \describe{ \item{applyTransform}{\code{signature(object = "PathSegment", tm = "matrix")}: When given a 3x3 numeric transformation matrix, the points in the segment are transformed, and produce a new object representing a path segment. Not intended to be used directly on path segments, but objects that inherit from path segments (e.g. the \code{"M"}, \code{"L"}, \code{"C"}, and \code{"Z"} operators. } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PathMoveTo}}, \code{\linkS4class{PathClosePath}}, \code{\linkS4class{PathLineTo}}, \code{\linkS4class{PathCurveTo}}. } grImport2/man/grid.picture.Rd0000654000176200001440000001104113560146550015603 0ustar liggesusers\name{grid.picture} \alias{pictureGrob} \alias{grid.picture} \title{ Draw a Picture Object. } \description{ These function take a \code{"Picture"} object and either draw the picture or create a grid graphical object representing the picture. } \usage{ pictureGrob(picture, x = unit(0.5, "npc"), y = unit(0.5, "npc"), width = unit(1, "npc"), height = unit(1, "npc"), just = "centre", hjust = NULL, vjust = NULL, default.units = "npc", expansion = 0.05, xscale = NULL, yscale = NULL, distort = FALSE, gpFUN = identity, ..., ext = c("none", "clipbbox", "gridSVG"), delayContent = match.arg(ext) == "gridSVG", name = NULL, prefix = NULL, clip = "on") grid.picture(...) } \arguments{ \item{picture}{ A \code{"Picture"} object. } \item{x}{ A single numeric value or unit object specifying an x-value. } \item{y}{ A single numeric value or unit object specifying a y-value. } \item{width}{ A single numeric value or unit object specifying a width. } \item{height}{ A single numeric value or unit object specifying a height. } \item{just}{ The justification of the picture relative to its (x, y) location. If there are two values, the first value specifes horizontal justification and the second value specifies vertical justification. Possible string values are: \code{"left"}, \code{"right"}, \code{"centre"}, \code{"center"}, \code{"bottom"}, and \code{"top"}. For numeric values, 0 means left alignment and 1 means right alignment. } \item{hjust}{ A numeric vector specifying horizontal justification. If specified, overrides the \code{just} setting. } \item{vjust}{ A numeric vector specifying vertical justification. If specified, overrides the \code{just} setting. } \item{default.units}{ A string indicating the default units to use if \code{x}, \code{y}, \code{width}, or \code{height} are only given as numeric vectors. } \item{expansion}{ An expansion factor; determines whether any space is left between the extent of the picture and the bounding rectangle it is drawn within. } \item{xscale}{ A numeric vector of length two indicating the minimum and maximum on the x-scale. } \item{yscale}{ A numeric vector of length two indicating the minimum and maximum on the y-scale. } \item{distort}{ A logical value indicating whether the image should preserve its aspect ratio or distort to fit the area it is being drawn within. } \item{gpFUN}{ A function that takes in a grid \code{gpar} object and returns a (optionally modified) \code{gpar} object. } \item{\dots}{ For \code{grid.picture}, arguments to be passed to \code{pictureGrob}. For \code{pictureGrob}, arguments to be passed to the picture object's \code{grobify} method. } \item{ext}{ A character vector. Selects from one of three possible extensions for drawing imported pictures. \code{"none"} means that no clipping will be applied to the imported picture. \code{"clipbbox"} means that clipping will be applied, but only to the bounding boxes of any imported clipping paths. \code{"gridSVG"} means that gridSVG will be used when drawing the \code{"Picture"} object, which enables the use of complex clipping paths, gradients, patterns, etc. to be rendered from an imported picture. } \item{delayContent}{ If \code{FALSE}, \code{pictureGrob()} generates a gTree with children immediately. If \code{TRUE}, \code{pictureGrob()} produces a gTree with a \code{makeContent()} method so that children are generated only at drawing time. The latter is relevant when \code{ext == "gridSVG"} because it affects when SVG definitions are registered. } \item{name}{ A character identifier. } \item{prefix}{ A character string. A prefix to add to referenced gridSVG content (e.g. pattern fills). Only used when \code{gridSVG} is \code{TRUE} (for \code{grobify}). The reference label must be a unique reference label, otherwise an error will result. This can be checked by calling gridSVG's \code{listSVGDefinitions()}. When this parameter is \code{NULL}, a prefix will automatically be generated but this is not guaranteed to be unique. } \item{clip}{ Clipping setting passed to the viewport that is set up for drawing the imported image. } } \value{ A grid gTree. } \author{ Simon Potter } \seealso{ \code{\link{grobify}}, \code{\link{grid.symbols}}. } grImport2/man/PictureDefinitions-class.Rd0000654000176200001440000000265213560671364020134 0ustar liggesusers\name{PictureDefinitions-class} \docType{class} \alias{PictureDefinitions-class} \alias{getDef} \alias{getDef-methods} \alias{setDef} \alias{setDef-methods} \alias{getDef,character-method} \alias{setDef,character,PictureContent-method} \title{Class \code{"PictureDefinitions"}} \description{ A collection of graphical content and features that are to be referenced by the rest of the image. These definitions are not intended to draw anything themselves, but describe how other pieces of graphical content will be drawn (or in the case of clipping paths, not drawn). } \section{Slots}{ \describe{ \item{\code{content}:}{ Object of class \code{"list"}. A list of \code{"PictureContent"} objects. } } } \section{Methods}{ \describe{ \item{getDef}{ \code{signature(id = "character")}: retrieves an object that is referred to by a given label. } \item{setDef}{ \code{signature(id = "character", value = "PictureContent")}: Not intended to be used by regular users, but this is a method for assigning a definition to be referenced later by \code{"PictureContent"} objects. This method stores a new definition (\code{value}) with a given label (\code{id}). The result is that a new \code{"PictureDefinitions"} object is returned with the new definition added to it. } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{Picture}} } grImport2/man/PictureClipPath-class.Rd0000654000176200001440000000466013557672572017376 0ustar liggesusers\name{PictureClipPath-class} \docType{class} \alias{PictureClipPath-class} \alias{grobify,PictureClipPath-method} \alias{applyTransform,PictureClipPath,matrix-method} \title{Class \code{"PictureClipPath"}} \description{ A description of a clipping path that is meant to be used as part of a larger picture (as it does not directly draw anything itself). This is primarily used for determining the bounding box of the clipping region (because R graphics only supports rectangular clipping regions). This object will have a greater effect with it is used in conjunction with the gridSVG package as it can apply non-rectangular clipping regions. } \section{Slots}{ \describe{ \item{\code{content}:}{ Object of class \code{"list"}. A list of \code{"PictureContent"} objects that describe the outline(s) of the clipping region(s). } \item{\code{label}:}{ Object of class \code{"character"}. A label to identify the clipping path by so that it may be referred to by content within the image. } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PictureClipPath", tm = "matrix")}: transforms the locations described by contents of the clip path object by a 3x3 transformation matrix and returns a \code{"PictureClipPath"} object whose children have had locations transformed by the matrix. } \item{grobify}{\code{signature(object = "PictureClipPath")}: convert the clipping path into a grid grob. Useful only in conjunction with the gridSVG package for non-rectangular paths. This \code{grobify} method takes three arguments: \describe{ \item{\code{defs}}{ Required. This argument expects a \code{"PictureDefinitions"} object that contains referenced content. } \item{\code{gpFUN}}{ A function that takes a \code{gpar} object and returns a modified \code{gpar} object. The default value for this arugment is the identity function. } \item{\code{ext}}{ A character vector. See \code{\link{grid.picture}} for more information on what this extension selection parameter means, in addition to the valid values this argument takes. } } } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PictureGroup}}. } grImport2/man/Picture-class.Rd0000654000176200001440000000434512231346762015734 0ustar liggesusers\name{Picture-class} \docType{class} \alias{Picture-class} \alias{[,Picture-method} \alias{[[,Picture-method} \alias{grobify,Picture-method} \title{Class "Picture"} \description{ A collection of paths, polylines, rectangles and other graphical content and features that together describe a picture. } \section{Objects from the Class}{ Objects can be created by calls of the form \code{new("Picture", ...)}. } \section{Slots}{ \describe{ \item{\code{content}:}{ A list of objects of class \code{"PictureContent"} that are paths, groups rectangles and other related objects. } \item{\code{defs}:}{ Object of class \code{"PictureDefinitions"} that contain all referenced content in the image. These are only used by the gridSVG package when "grobifying" an image. } \item{\code{summary}:}{ Object of class \code{"PictureSummary"} that describes the scales applied to this picture. } } } \section{Methods}{ \describe{ \item{[}{ \code{signature(x = "Picture")}: subset the content of a picture to produce a new picture (including a new, updated summary). } \item{[[}{ \code{signature(x = "Picture")}: extract a single piece of a picture object, to produce a new picture (including a new, updated summary). } \item{grobify}{ \code{signature(object = "Picture")}: convert a picture into a grid grob (for use as a one-off image). This method contains two additional arguments: \describe{ \item{\code{gpFUN}}{ This argument expects to take a function that modifies a \code{gpar} object. For its input, this function should take a \code{gpar} object, modify that object, and then return it. By default the value of this argument is the identity function. } \item{\code{ext}}{ A character vector. See \code{\link{grid.picture}} for more information on what this extension selection parameter means, in addition to the valid values this argument takes. } } } } } \author{ Simon Potter } \seealso{ \code{\link{readPicture}}, \code{\link{grid.picture}}, \code{\link{PictureSummary-class}}. } \keyword{classes} grImport2/man/PathData-class.Rd0000654000176200001440000000152212207234375016000 0ustar liggesusers\name{PathData-class} \docType{class} \alias{PathData-class} \alias{applyTransform,PathData,matrix-method} \title{Class \code{"PathData"}} \description{ An object that represents a sequence of path data segments in an SVG path. } \section{Slots}{ \describe{ \item{\code{segments}:}{Object of class \code{"list"} ~~ } } } \section{Methods}{ \describe{ \item{applyTransform}{\code{signature(object = "PathData", tm = "matrix")}: A transformation matrix to apply to all path segments in the path that \code{object} contains. Returns a new \code{"PathData"} object with each path segment transformed to their new locations. } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PathData}}, \code{\linkS4class{PathMoveTo}}, \code{\linkS4class{PathLineTo}}, \code{\linkS4class{PathCurveTo}}. } grImport2/man/PathLineTo-class.Rd0000654000176200001440000000141412207234375016321 0ustar liggesusers\name{PathLineTo-class} \docType{class} \alias{PathLineTo-class} \title{Class \code{"PathLineTo"}} \description{ A description of a path line to operator (\code{"L"} in SVG parlance) that is meant to be used as part of a path. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. The x-location that the path is going to draw a line to. } \item{\code{y}:}{ Object of class \code{"numeric"}. The y-location that the path is going to draw a line to. } } } \section{Extends}{ Class \code{\linkS4class{PathSegment}}, directly. } \author{ Simon Potter } \seealso{ \code{\linkS4class{PathData}}, \code{\linkS4class{PathMoveTo}}, \code{\linkS4class{PathClosePath}}, \code{\linkS4class{PathCurveTo}}. } grImport2/man/PictureGradientStop-class.Rd0000654000176200001440000000213312207234375020250 0ustar liggesusers\name{PictureGradientStop-class} \docType{class} \alias{PictureGradientStop-class} \alias{grobify,PictureGradientStop-method} \title{Class \code{"PictureGradientStop"}} \description{ A description of a gradient stop that is meant to be used as part of a larger picture (as it does not directly draw anything itself). This object will have no effect unless it is used in conjunction with the gridSVG package. } \section{Slots}{ \describe{ \item{\code{offset}:}{ Object of class \code{"numeric"}. The offset (usually between 0 and 1) from the start of the gradient. These represent locations to place the colours (\code{col}) at. } \item{\code{col}:}{ Object of class \code{"character"}. A colour in the form \code{"#RRGGBBAA"}. } } } \section{Methods}{ \describe{ \item{grobify}{\code{signature(object = "PictureGradientStop")}: convert to a gradient stop object for use with the gridSVG package. } } } \author{ Simon Potter } \seealso{ \code{\linkS4class{PictureLinearGradient}}, \code{\linkS4class{PictureRadialGradient}}. } grImport2/man/PictureMask-class.Rd0000654000176200001440000000351013557672600016546 0ustar liggesusers\name{PictureMask-class} \docType{class} \alias{PictureMask-class} \alias{grobify,PictureMask-method} \alias{applyTransform,PictureMask,matrix-method} \title{Class \code{"PictureMask"}} \description{ A description of a luminance mask. } \section{Slots}{ \describe{ \item{\code{content}:}{ Object of class \code{"list"}. A list of \code{"PictureContent"} objects that are use to define the mask. Typically objects that actually draw content (e.g. a path or a rect). } } } \section{Extends}{ Class \code{\linkS4class{PictureContent}}, directly. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PictureMask", tm = "matrix")}: transforms the locations described by contents of the mask object by a 3x3 transformation matrix and returns a \code{"PictureMask"} object whose children have had locations transformed by the matrix. } \item{grobify}{ \code{signature(object = "PictureMask")}: creates a mask object for use with the gridSVG package. Not intended to be used directly. There are three arguments to this \code{grobify} method: \describe{ \item{\code{defs}}{ An object of class \code{"PictureDefinitions"}. This object is primarily useful in conjunction with the gridSVG package. } \item{\code{gpFUN}}{ This argument takes a function that takes a \code{gpar} object and returns a modified \code{gpar} object. The default value is the identity function. } \item{\code{ext}}{ A character vector. See \code{\link{grid.picture}} for more information on what this extension selection parameter means, in addition to the valid values this argument takes. } } } } } \author{ Simon Potter } grImport2/man/applyTransform.Rd0000654000176200001440000000100112207234375016220 0ustar liggesusers\name{applyTransform} \alias{applyTransform} \title{ Transform a Picture Object by a Transformation Matrix } \description{ Transforms a \code{"Picture"} object (or indeed \code{"PictureContent"} objects) using a 3x3 transformation matrix. } \usage{ applyTransform(object, tm) } \arguments{ \item{object}{ Either a \code{"Picture"} object or a \code{"PictureContent"} object. } \item{tm}{ A 3x3 numeric transformation matrix. } } \value{ The transformed object. } \author{ Simon Potter } grImport2/man/PictureLinearGradient-class.Rd0000654000176200001440000000373312207234375020544 0ustar liggesusers\name{PictureLinearGradient-class} \docType{class} \alias{PictureLinearGradient-class} \alias{applyTransform,PictureLinearGradient,matrix-method} \alias{grobify,PictureLinearGradient-method} \title{Class "PictureLinearGradient" } \description{ A description of a linear gradient that is meant to be used as part of a larger picture (as it does not directly draw anything itself). This object will have no effect unless it is used in conjunction with the gridSVG package. } \section{Slots}{ \describe{ \item{\code{x0}:}{ Object of class \code{"numeric"}. The starting x-location of the linear gradient. } \item{\code{y0}:}{ Object of class \code{"numeric"}. The starting y-location of the linear gradient. } \item{\code{x1}:}{ Object of class \code{"numeric"}. The ending x-location of the linear gradient. } \item{\code{y1}:}{ Object of class \code{"numeric"}. The ending y-location of the linear gradient. } \item{\code{spreadMethod}:}{ Object of class \code{"character"} that specifies what happens when a gradient ends within its bounds. Must be one of "pad", "reflect" or "repeat". See \code{"linearGradient"} in the gridSVG package for more information. } \item{\code{stops}:}{ Object of class \code{"list"} that is a list of objects of class \code{"PictureGradientStop"}. } } } \section{Extends}{ Class \code{"PictureContent"}. } \section{Methods}{ \describe{ \item{applyTransform}{ \code{signature(object = "PictureLinearGradient", tm = "matrix")}: transform the locations that represent the bounds and direction of the gradient by a 3x3 transformation matrix. } \item{grobify}{\code{signature(object = "PictureLinearGradient")}: convert to a gradient object for use with the gridSVG package. } } } \author{ Simon Potter } \seealso{ \code{\link{Picture-class}}, \code{\link{grid.picture}}. } \keyword{classes} grImport2/man/PathCurveTo-class.Rd0000654000176200001440000000156512207234375016525 0ustar liggesusers\name{PathCurveTo-class} \docType{class} \alias{PathCurveTo-class} \title{Class \code{"PathCurveTo"}} \description{ A description of a path curve to operator (\code{"C"} in SVG parlance) that is meant to be used as part of a path. } \section{Slots}{ \describe{ \item{\code{x}:}{ Object of class \code{"numeric"}. A vector of length four that represent the x-locations of the control points of a cubic bezier curve. } \item{\code{y}:}{ Object of class \code{"numeric"}. A vector of length four that represent the y-locations of the control points of a cubic bezier curve. } } } \section{Extends}{ Class \code{\linkS4class{PathSegment}}, directly. } \author{ Simon Potter } \seealso{ \code{\linkS4class{PathData}}, \code{\linkS4class{PathMoveTo}}, \code{\linkS4class{PathLineTo}}, \code{\linkS4class{PathClosePath}}. } grImport2/DESCRIPTION0000755000176200001440000000316013567034712013660 0ustar liggesusersPackage: grImport2 Version: 0.2-0 Depends: R (>= 2.12.0) Imports: methods, grDevices, grid, XML, png, jpeg, base64enc Suggests: gridSVG, rsvg Title: Importing 'SVG' Graphics Authors@R: c(person("Simon", "Potter", role = c("aut"), email = "simon.potter@auckland.ac.nz"), person("Paul", "Murrell", role = c("aut", "cre"), email = "paul@stat.auckland.ac.nz", comment = c(ORCID = "0000-0002-3224-8858"))) Description: Functions for importing external vector images and drawing them as part of 'R' plots. This package is different from the 'grImport' package because, where that package imports 'PostScript' format images, this package imports 'SVG' format images. Furthermore, this package imports a specific subset of 'SVG', so external images must be preprocessed using a package like 'rsvg' to produce 'SVG' that this package can import. 'SVG' features that are not supported by 'R' graphics, e.g., gradient fills, can be imported and then exported via the 'gridSVG' package. URL: https://r-forge.r-project.org/projects/grimport/,https://stattech.wordpress.fos.auckland.ac.nz/2013/09/,https://stattech.wordpress.fos.auckland.ac.nz/2016/08/30/2016-11-the-butterfly-affectation/,https://stattech.wordpress.fos.auckland.ac.nz/2019/11/25/2019-02-svg-in-svg-out/ License: GPL (>= 2) NeedsCompilation: no Packaged: 2019-11-25 20:03:35 UTC; pmur002 Author: Simon Potter [aut], Paul Murrell [aut, cre] () Maintainer: Paul Murrell Repository: CRAN Date/Publication: 2019-11-25 20:30:02 UTC grImport2/tests/0000755000176200001440000000000013252574763013317 5ustar liggesusersgrImport2/tests/test-clip-input.svg0000654000176200001440000000645412211204573017072 0ustar liggesusers grImport2/tests/test-raster-output.svg.save0000654000176200001440000000720613252340102020570 0ustar liggesusers grImport2/tests/test-path-complex-input.svg0000654000176200001440000034220012211204573020534 0ustar liggesusers grImport2/tests/test-rect-output.svg.save0000654000176200001440000000246213252574705020246 0ustar liggesusers grImport2/tests/test-clip.R0000654000176200001440000000220713252574334015342 0ustar liggesuserslibrary(grid) library(grImport2) library(gridSVG) pic <- readPicture("test-clip-input.svg") gridsvg("test-noclip-output.svg", width = 6, height = 6, annotate=FALSE) grid.picture(pic, expansion = 0) dev.off() gridsvg("test-bboxclip-output.svg", width = 6, height = 6, annotate=FALSE) grid.picture(pic, expansion = 0, ext="clipbbox") dev.off() ## Encoding in SVG file (on line 1) differs by platform model <- readLines("test-noclip-output.svg.save")[-1] test <- readLines("test-noclip-output.svg")[-1] same <- model == test if (! all(same)) { stop(paste0("noclip output not equal to expected output", "------------------", model[!same], "------------------", test[!same], collapse="\n")) } model <- readLines("test-bboxclip-output.svg.save")[-1] test <- readLines("test-bboxclip-output.svg")[-1] same <- model == test if (! all(same)) { stop(paste0("bboxclip output not equal to expected output", "------------------", model[!same], "------------------", test[!same], collapse="\n")) } grImport2/tests/test-paths.R0000654000176200001440000000306413463720216015530 0ustar liggesuserslibrary(grid) library(grImport2) library(gridSVG) pic <- readPicture("test-path-simple-input.svg") gridsvg("test-path-simple-output.svg", width = 6, height = 6, annotate = FALSE) grid.picture(pic, expansion = 0) dev.off() pic <- readPicture("test-path-complex-input.svg") gridsvg("test-path-complex-output.svg", width = 6, height = 6, annotate = FALSE) grid.picture(pic, expansion = 0) dev.off() ## Encoding in SVG file (on line 1) differs by platform model <- readLines("test-path-simple-output.svg.save")[-1] test <- readLines("test-path-simple-output.svg")[-1] same <- model == test if (! all(same)) { stop(paste0("path-simple output not equal to expected output", "------------------", model[!same], "------------------", test[!same], collapse="\n")) } model <- readLines("test-path-complex-output.svg.save")[-1] test <- readLines("test-path-complex-output.svg")[-1] same <- model == test if (! all(same)) { ## Protect against tiny rounding differences in locations x <- suppressWarnings(lapply(strsplit(model[!same], " "), as.numeric)) y <- suppressWarnings(lapply(strsplit(test[!same], " "), as.numeric)) rx <- unlist(lapply(x, round, 1)) ry <- unlist(lapply(y, round, 1)) if (!all.equal(rx, ry)) { stop(paste0("path-complex output not equal to expected output", "------------------", model[!same], "------------------", test[!same], collapse="\n")) } } grImport2/tests/test-rect-input.svg0000654000176200001440000000054713252574023017103 0ustar liggesusers grImport2/tests/test-path-complex-output.svg.save0000654000176200001440000133051713252337747021723 0ustar liggesusers grImport2/tests/test-symbol.R0000654000176200001440000000120613252574472015721 0ustar liggesuserslibrary(grid) library(grImport2) library(gridSVG) pic <- readPicture("test-symbol-input.svg") gridsvg("test-symbol-output.svg", width = 6, height = 6, annotate = FALSE) grid.picture(pic, expansion = 0) dev.off() ## Encoding in SVG file (on line 1) differs by platform model <- readLines("test-symbol-output.svg.save")[-1] test <- readLines("test-symbol-output.svg")[-1] same <- model == test if (! all(same)) { stop(paste0("symbol output not equal to expected output", "------------------", model[!same], "------------------", test[!same], collapse="\n")) } grImport2/tests/test-symbol-output.svg.save0000654000176200001440000006314613252340311020604 0ustar liggesusers grImport2/tests/test-path-simple-input.svg0000654000176200001440000000103012211204573020347 0ustar liggesusers grImport2/tests/test-path-simple-output.svg.save0000654000176200001440000000333013252337742021525 0ustar liggesusers grImport2/tests/test-symbol-input.svg0000654000176200001440000001255412211204573017446 0ustar liggesusers grImport2/tests/test-rect.R0000654000176200001440000000117513252574256015356 0ustar liggesuserslibrary(grid) library(grImport2) library(gridSVG) pic <- readPicture("test-rect-input.svg") gridsvg("test-rect-output.svg", width = 6, height = 6, annotate = FALSE) grid.picture(pic, expansion = 0) dev.off() ## Encoding in SVG file (on line 1) differs by platform model <- readLines("test-rect-output.svg.save")[-1] test <- readLines("test-rect-output.svg")[-1] same <- model == test if (! all(same)) { stop(paste0("rect output not equal to expected output", "------------------", model[!same], "------------------", test[!same], collapse="\n")) } grImport2/tests/test-raster.R0000654000176200001440000000146413252574537015724 0ustar liggesuserslibrary(grid) library(grImport2) library(gridSVG) pic <- readPicture("test-raster-input.svg") gridsvg("test-raster-output.svg", width = 6, height = 6, annotate = FALSE) grid.picture(pic, expansion = 0) dev.off() ## This test is not run be default because it is sensitive to changes ## in the temporary PNG file that is created when exporting raster ## to SVG via 'gridSVG' notrun <- function() { model <- readLines("test-raster-output.svg.save")[-1] test <- readLines("test-raster-output.svg")[-1] same <- model == test if (! all(same)) { stop(paste0("raster output not equal to expected output", "------------------", model[!same], "------------------", test[!same], collapse="\n")) } } grImport2/tests/test-noclip-output.svg.save0000654000176200001440000003466413252337455020605 0ustar liggesusers grImport2/tests/test-bboxclip-output.svg.save0000654000176200001440000003567413252337456021126 0ustar liggesusers grImport2/tests/test-raster-input.svg0000654000176200001440000000073512211204573017437 0ustar liggesusers grImport2/R/0000755000176200001440000000000013567031627012352 5ustar liggesusersgrImport2/R/classes.R0000654000176200001440000005024613562647021014136 0ustar liggesusers# Import some S3 classes setOldClass("gpar") setOldClass("nativeRaster") # We need to be able to transform objects when we create them # we can do this via a transformation matrix acting upon the original object setGeneric("applyTransform", function(object, tm) { standardGeneric("applyTransform") }) # Method useful for tracking the bounding boxes of the content of the image. # Mostly useful for being able to reduce a picture and its bounding box # to only a subset of the image. setGeneric("getbbox", function(object, tm) { standardGeneric("getbbox") }) # Method for turning a picture object into a grid graphics object setGeneric("grobify", function(object, ...) { standardGeneric("grobify") }) setGeneric("symbolize", function(object, x = unit(0.5, "npc"), y = unit(0.5, "npc"), size = unit(1, "npc"), default.units = "npc", ...) { standardGeneric("symbolize") }) # Empty base class, just ensures that we can test whether # children are valid pieces of a picture setClass("PictureContent") setClass("PictureClipPath", representation("PictureContent", content = "list", label = "character")) setValidity("PictureClipPath", function(object) { length(object@content) && all(sapply(object@content, is, "PictureContent")) }) setClass("PictureFeColorMatrix", representation("PictureContent", type = "character", input = "character", values = "matrix")) setClass("PictureFilter", representation("PictureContent", filterUnits = "character", x = "numeric", y = "numeric", width = "numeric", height = "numeric", content = "PictureFeColorMatrix")) setClass("PictureGroup", representation("PictureContent", content = "list", clip = "ANY", maskRef = "ANY", filterRef = "ANY", gp = "gpar")) setValidity("PictureGroup", function(object) { # mask and filter can be ["NULL"|"character"] if (! is.null(object@maskRef) && ! is.character(object@maskRef)) return(FALSE) if (! is.null(object@filterRef) && ! is.character(object@filterRef)) return(FALSE) # Must have content and only "PictureContent". # Furthermore, only allow no clipping or a clipping path # object, essentially the representation of 'clip' is # ["NULL"|"PictureClipPath"]. if (length(object@content)) all(sapply(object@content, is, "PictureContent")) && (is.null(object@clip) || is(object@clip, "PictureClipPath")) else (is.null(object@clip) || is(object@clip, "PictureClipPath")) }) setClass("PictureImage", representation("PictureContent", x = "numeric", y = "numeric", width = "numeric", height = "numeric", angle = "numeric", image = "nativeRaster", maskRef = "ANY", bbox = "numeric")) setClass("PictureMask", representation("PictureContent", content = "list")) setValidity("PictureMask", function(object) { length(object@content) && all(sapply(object@content, is, "PictureContent")) }) # See paths.R for path segments and methods # Definition of PathData must come before PicturePath setClass("PathData", representation(segments = "list")) setValidity("PathData", function(object) { all(sapply(object@segments, is, "PathSegment")) }) setClass("PicturePath", representation("PictureContent", d = "PathData", rule = "character", gp = "gpar", bbox = "numeric")) setClass("PicturePattern", representation("PictureContent", x = "numeric", y = "numeric", width = "numeric", height = "numeric", angle = "numeric", definition = "list")) setClass("PictureRadialGradient", representation("PictureContent", x = "numeric", y = "numeric", r = "numeric", fx = "numeric", fy = "numeric", spreadMethod = "character", stops = "list")) setValidity("PictureRadialGradient", function(object) { all(sapply(object@stops, is, "PictureGradientStop")) }) setClass("PictureLinearGradient", representation("PictureContent", x0 = "numeric", y0 = "numeric", x1 = "numeric", y1 = "numeric", spreadMethod = "character", stops = "list")) setValidity("PictureLinearGradient", function(object) { all(sapply(object@stops, is, "PictureGradientStop")) }) setClass("PictureGradientStop", representation(offset = "numeric", col = "character")) setClass("PictureRect", representation("PictureContent", x = "numeric", y = "numeric", width = "numeric", height = "numeric", angle = "numeric", gp = "gpar", bbox = "numeric")) setClass("PictureSymbol", representation("PictureContent", definition = "list")) # Content should be a named list setClass("PictureDefinitions", representation(content = "list"), prototype(content = list())) setGeneric("getDef", function(id) standardGeneric("getDef")) setMethod("getDef", signature(id = "character"), function(id) { defList <- get("defs", .grImport2Env) defList@content[[id]] }) setGeneric("setDef", function(id, value) standardGeneric("setDef")) setMethod("setDef", signature(id = "character", value = "PictureContent"), function(id, value) { defList <- get("defs", .grImport2Env) defList@content[[id]] <- value assign("defs", defList, .grImport2Env) }) setClass("PictureSummary", representation(xscale = "numeric", yscale = "numeric")) setClass("Picture", representation(content = "list", defs = "PictureDefinitions", summary = "PictureSummary")) setValidity("Picture", function(object) { all(sapply(object@content, is, "PictureContent")) }) setMethod("[", "Picture", function(x, i, j, drop) { content <- x@content[i] allBounds <- lapply(content, getbbox) xmin <- min(sapply(allBounds, function(x) x[1])) xmax <- max(sapply(allBounds, function(x) x[2])) ymin <- min(sapply(allBounds, function(x) x[3])) ymax <- max(sapply(allBounds, function(x) x[4])) bbox <- c(xmin, xmax, ymin, ymax) summary <- new("PictureSummary", xscale = bbox[1:2], yscale = rev(bbox[3:4])) new("Picture", content = content, defs = x@defs, summary = summary) }) setMethod("[[", "Picture", function(x, i, j, drop) { if (length(i) > 1) stop("index must be length 1") x@content[[i]] }) setMethod("[", "PictureGroup", function(x, i, j, drop) { content <- x@content[i] new("PictureGroup", content = content, clip = x@clip, gp = x@gp) }) setMethod("[[", "PictureGroup", function(x, i, j, drop) { if (length(i) > 1) stop("index must be length 1") x@content[[i]] }) # This is different from applyTransform() method for "PictureLinearGradient" # This one works from a *reference* (by name) to a "PictureLinearGradient" # that already exists in a list of definitions, so has to do the look up # using the name to get a "PictureLinearGradient" # (actually it is more general than that because it could be working with # a radial gradient fill or a pattern fill, not just a linear gradient fill) # The existing definition is modified to create a new definition, with # a new name, and the new name (reference to the new definition) is returned # NOTE that if the name does not identify a known definition then the # function silently returns the old name transformRegisteredDef <- function(id, tm) { def <- getDef(id) if (! is.null(def)) { newDef <- applyTransform(def, tm) newId <- updateId(id) setDef(newId, newDef) id <- newId } id } ## Different again because need to transform the clip path itself ## and the registered definition transformClipPath <- function(cp, tm) { id <- cp@label def <- getDef(id) if (! is.null(def)) { newDef <- applyTransform(def, tm) newId <- updateId(id) setDef(newId, newDef) cp@label <- newId } applyTransform(cp, tm) } setMethod("applyTransform", signature(object = "gpar", tm = "matrix"), function(object, tm) { gparNames <- names(object) ul <- matrix(c(0, 1/sqrt(2), 0, 1/sqrt(2), rep(1, 2)), ncol = 3) for (i in seq_len(nrow(ul))) ul[i, ] <- tm %*% ul[i, ] scaleFactor <- sqrt((ul[1, 1] - ul[2, 1])^2 + (ul[1, 2] - ul[2, 2])^2) if ("lwd" %in% gparNames) object$lwd <- abs(object$lwd * scaleFactor) if ("lty" %in% gparNames) object$lty <- abs(object$lty * scaleFactor) if ("gradientFill" %in% gparNames) object$gradientFill <- transformRegisteredDef(object$gradientFill, tm) if ("patternFill" %in% gparNames) object$patternFill <- transformRegisteredDef(object$patternFill, tm) object }) setMethod("applyTransform", signature(object = "PictureLinearGradient", tm = "matrix"), function(object, tm) { locs <- matrix(c(object@x0, object@x1, object@y0, object@y1, rep(1, 2)), ncol = 3) for (i in seq_len(nrow(locs))) locs[i, ] <- tm %*% locs[i, ] object@x0 <- locs[1, 1] object@y0 <- locs[1, 2] object@x1 <- locs[2, 1] object@y1 <- locs[2, 2] object }) setMethod("applyTransform", signature(object = "PictureRadialGradient", tm = "matrix"), function(object, tm) { locs <- matrix(c(object@x, object@fx, object@y, object@fy, rep(1, 2)), ncol = 3) for (i in seq_len(nrow(locs))) locs[i, ] <- tm %*% locs[i, ] ## Just interested in scaling (not translation) for radius tm[,3] <- c(0, 0, 1) ## (assuming no shear) tr <- tm %*% c(object@r, 0, 1) object@x <- locs[1, 1] object@y <- locs[1, 2] object@fx <- locs[2, 1] object@fy <- locs[2, 2] object@r <- sqrt(tr[1]^2 + tr[2]^2) object }) setGeneric("transformPatternContent", function(object, tm) standardGeneric("transformPatternContent")) setMethod("transformPatternContent", signature(object = "PictureImage", tm = "matrix"), function(object, tm) { object@width <- object@width*tm[1, 1] object@height <- object@height*tm[2, 2] object }) setMethod("transformPatternContent", signature(object = "ANY", tm = "matrix"), function(object, tm) { object }) setMethod("applyTransform", signature(object = "PicturePattern", tm = "matrix"), function(object, tm) { object@definition <- lapply(object@definition, transformPatternContent, tm) object <- transformRect(object, tm) object }) setMethod("applyTransform", signature(object = "PictureGroup", tm = "matrix"), function(object, tm) { object@content <- lapply(object@content, applyTransform, tm) object@gp <- applyTransform(object@gp, tm) ## If there is a clip path or a mask, also transform those if (!is.null(object@clip)) { object@clip <- transformClipPath(object@clip, tm) } if (length(object@maskRef)) { ## !(NULL or character(0)) object@maskRef <- transformRegisteredDef(object@maskRef, tm) } object }) setMethod("applyTransform", signature(object = "PictureClipPath", tm = "matrix"), function(object, tm) { object@content <- lapply(object@content, applyTransform, tm) object }) setMethod("applyTransform", signature(object = "PictureMask", tm = "matrix"), function(object, tm) { object@content <- lapply(object@content, applyTransform, tm) object }) # Really only need to be applied to the path data itself setMethod("applyTransform", signature(object = "PicturePath", tm = "matrix"), function(object, tm) { object@d <- applyTransform(object@d, tm) object@gp <- applyTransform(object@gp, tm) points <- getPoints(object@d, line = TRUE) object@bbox <- c(min(points$x), max(points$x), min(points$y), max(points$y)) object }) transformRect <- function(object, tm) { # Get new x, y, width, height, and angle from # original x, y, width, height, and transform ## https://math.stackexchange.com/questions/13150/extracting-rotation-scale-values-from-2d-transformation-matrix a <- tm[1, 1] b <- tm[1, 2] c <- tm[2, 1] d <- tm[2, 2] e <- tm[1, 3] f <- tm[2, 3] delta <- a * d - b * c translation <- c(e, f) if (a != 0 || b != 0) { r <- sqrt(a * a + b * b) rotation <- if (b > 0) acos(a / r) else -acos(a / r) scale <- c(r, delta / r) skew <- c(atan((a * c + b * d) / (r * r)), 0) } else if (c != 0 || d != 0) { s <- sqrt(c * c + d * d) rotation <- pi / 2 - if (d > 0) acos(-c / s) else -acos(c / s) scale <- c(delta / s, s) skew <- c(0, atan((a * c + b * d) / (s * s))) } else { ## a = b = c = d = 0 warning("Zero transformation matrix") } if (any(skew != 0)) { warning("Skew transformation matrix") } object@x <- object@x + translation[1] object@y <- object@y + translation[2] object@width <- scale[1]*object@width object@height <- scale[2]*object@height object@angle <- object@angle + rotation object } ALTtransformRect <- function(object, tm) { # Get new x, y, width, height, and angle from # original x, y, width, height, and transform loc <- tm %*% c(object@x, object@y, 1) object@x <- loc[1, 1] object@y <- loc[2, 1] sx <- sqrt(tm[1, 1]^2 + tm[1, 2]^2) if (tm[1, 1] < 0) sx <- -sx sy <- sqrt(tm[2, 1]^2 + tm[2, 2]^2) if (tm[2, 2] < 0) sy <- -sy object@width <- sx*object@width object@height <- sy*object@height # Remove translation tm[1, 3] <- 0 tm[2, 3] <- 0 # Remove scaling tm[1, 1] <- tm[1, 1]/sx tm[1, 2] <- tm[1, 2]/-sy tm[2, 1] <- tm[2, 1]/sx tm[2, 2] <- tm[2, 2]/sy # Rotate (1, 0) = positive x-axis to get angle loc <- tm %*% c(1, 0, 1) angle <- atan2(loc[2, 1], loc[1, 1]) object@angle <- object@angle + angle object } transformRectBBox <- function(object, tm) { locs <- matrix(c(object@x, object@x + object@width, object@x, object@x + object@width, object@y, object@y + object@height, object@y + object@height, object@y, rep(1, 4)), ncol = 3) for (i in seq_len(nrow(locs))) locs[i, ] <- tm %*% locs[i, ] c(min(locs[, 1]), max(locs[, 1]), min(locs[, 2]), max(locs[, 2])) } setMethod("applyTransform", signature(object = "PictureRect", tm = "matrix"), function(object, tm) { # Must transform bbox before transforming object itself # (which modifies object's x,y,width,height) object@bbox <- transformRectBBox(object, tm) object <- transformRect(object, tm) object@gp <- applyTransform(object@gp, tm) object }) setMethod("applyTransform", signature(object = "PictureImage", tm = "matrix"), function(object, tm) { # Must transform bbox before transforming object itself # (which modifies object's x,y,width,height) object@bbox <- transformRectBBox(object, tm) object <- transformRect(object, tm) ## If there is a mask, also transform that if (length(object@maskRef)) { ## !(NULL or character(0)) object@maskRef <- transformRegisteredDef(object@maskRef, tm) } object }) getbboxFromList <- function(x) { allBounds <- lapply(x, getbbox) xmin <- min(sapply(allBounds, function(x) x[1])) xmax <- max(sapply(allBounds, function(x) x[2])) ymin <- min(sapply(allBounds, function(x) x[3])) ymax <- max(sapply(allBounds, function(x) x[4])) c(xmin, xmax, ymin, ymax) } setMethod("getbbox", signature(object = "list"), function(object) { getbboxFromList(object) }) setMethod("getbbox", signature(object = "PictureClipPath"), function(object) { getbboxFromList(object@content) }) setMethod("getbbox", signature(object = "PictureImage"), function(object) { object@bbox }) setMethod("getbbox", signature(object = "PictureRect"), function(object) { object@bbox }) setMethod("getbbox", signature(object = "PictureGroup"), function(object) { getbboxFromList(object@content) }) setMethod("getbbox", signature(object = "PicturePath"), function(object) { object@bbox }) grImport2/R/utils.R0000654000176200001440000002010713560665746013646 0ustar liggesusers# Need to be able to read in rasters in-memory # Expects a base64 encoded image string, returns a native raster (or NULL) readBase64Image <- function(x) { # Cairo only uses png, jpeg, or URI references # ignore URI references pngHeader <- "data:image/png;base64," jpegHeader <- "data:image/jpeg;base64," header <- if (substring(x, 1, nchar(pngHeader)) == pngHeader) pngHeader else if (substring(x, 1, nchar(jpegHeader)) == jpegHeader) jpegHeader else NULL # Give up, could be a URI if (is.null(header)) return(NULL) base64Data <- substring(x, nchar(header) + 1, nchar(x)) if (header == pngHeader) readPNG(base64decode(base64Data), native = TRUE) else readJPEG(base64decode(base64Data), native = TRUE) } svgStyleToList <- function(styleAttr) { if (is.null(styleAttr)) return(list()) attrs <- strsplit(styleAttr, ";")[[1]] attrs <- attrs[nzchar(attrs)] attrs <- unlist(strsplit(attrs, " ")) splitAttrs <- strsplit(attrs[nzchar(attrs)], ":") gparNames <- sapply(splitAttrs, function(x) { switch(x[1], fill = "fill", "font-family" = "fontfamily", "fill-opacity" = "fillAlpha", "font-style" = "fontstyle", "font-size" = "fontsize", "font-weight" = "fontweight", opacity = "alpha", stroke = "col", "stroke-dasharray" = "lty", "stroke-linecap" = "lineend", "stroke-linejoin" = "linejoin", "stroke-miterlimit" = "linemitre", "stroke-opacity" = "colAlpha", "stroke-width" = "lwd", x[1]) }) gpars <- lapply(splitAttrs, function(x) { # Attempt to cast to numeric, if NA, must be char num <- suppressWarnings(as.numeric(x[2])) if (! is.na(num)) { num } else { # Switch a few SVG values to grid parlance switch(x[2], nonzero = "winding", x[2]) } }) names(gpars) <- gparNames if ("lty" %in% names(gpars)) gpars$lty <- parseLty(gpars$lty) # Also change all of the references to gradient or pattern # fills/strokes to patternFill="" or gradientStroke="", etc if ("col" %in% names(gpars) && is.urlref(gpars$col)) { id <- urlToID(gpars$col) colType <- class(getDef(id)) if (colType == "PicturePattern") gpars$patternStroke <- id else gpars$gradientStroke <- id gpars$col <- NULL } if ("fill" %in% names(gpars) && is.urlref(gpars$fill)) { id <- urlToID(gpars$fill) fillType <- class(getDef(id)) if (fillType == "PicturePattern") gpars$patternFill <- id else gpars$gradientFill <- id gpars$fill <- NULL } gpars } parseLty <- function(x) { if (x == "none") 1 # solid else as.numeric(strsplit(x, ",")[[1]]) } # Pull out all of the gpar settings svgStyleListToGpar <- function(style) { style <- resolveColours(style) gparNames <- c("alpha", "cex", "col", "fill", "font", "fontfamily", "fontsize", "lex", "lineend", "lineheight", "linejoin", "linemitre", "lty", "lwd", "gradientFill", "gradientStroke", "patternFill", "patternStroke") styleNames <- names(style) gparInds <- which(styleNames %in% gparNames) if (! length(gparInds)) return(gpar()) else { # Fix up broken spelling gparSub <- style[gparInds] ljoinInd <- which("linejoin" == names(gparSub)) if (length(ljoinInd) && gparSub[[ljoinInd]] == "miter") gparSub[[ljoinInd]] <- "mitre" do.call("gpar", gparSub) } } # Turn fill-opacity & fill, along with stroke-opacity and stroke from # [0,1] + rgb(%,%,%) into a hex quad, i.e. #RRGGBBAA resolveColours <- function(x) { rgba2col <- function(col, alpha) { if (col == "none") return("#FFFFFF00") # Remove "rgb(" and ")" # Also split into numbers col <- as.numeric( strsplit( strsplit(substring(col, 5, nchar(col) - 1), ",")[[1]], "%")) if (is.na(alpha)) rgb(col[1], col[2], col[3], maxColorValue = 100) else rgb(col[1], col[2], col[3], as.numeric(alpha) * 100, maxColorValue = 100) } gparNames <- names(x) # col if ("colAlpha" %in% gparNames && "col" %in% gparNames) { if (! is.urlref(x$col)) { x$col <- rgba2col(x$col, x$colAlpha) x <- x[gparNames != "colAlpha"] } } else if ("col" %in% gparNames) { if (! is.urlref(x$col)) x$col <- rgba2col(x$col, NA) } # fill if ("fillAlpha" %in% gparNames && "fill" %in% gparNames) { if (! is.urlref(x$fill)) { x$fill <- rgba2col(x$fill, x$fillAlpha) x <- x[gparNames != "fillAlpha"] } } else if ("fill" %in% gparNames) { if (! is.urlref(x$fill)) x$fill <- rgba2col(x$fill, NA) } x } is.urlref <- function(x) { substring(x, 1, 3) == "url" } urlToID <- function(x) { # Remove first five chars "url(#" and last char ")" substring(x, 6, nchar(x) - 1) } hrefToID <- function(x) { # Remove "#" substring(x, 2, nchar(x)) } isRectangular <- function(x) { # Pull out the line points because they will have the close path # segments too (necessary!) xs <- convertX(x$children[[2]]$x, "native", valueOnly = TRUE) ys <- convertY(x$children[[2]]$y, "native", valueOnly = TRUE) # Do not need to check for ys because they are guaranteed to be # the same length if (length(xs) != 5) { FALSE } else { # Line points must join up if (xs[1] != xs[5] || ys[1] != ys[5]) return(FALSE) xs <- xs[1:4] ys <- ys[1:4] # Need to find the centre of of the rectangle # Then if the square of the distances are equal then we # know we have a rectangle cx <- mean(xs) cy <- mean(ys) dists <- (cx - xs)^2 + (cy - ys)^2 # Check that all are equal with a small amount of tolerance isRect <- all(abs(dists - mean(dists)) < 0.00001) if (! isRect) return(FALSE) # Now to check whether there has been any rotation applied # FIXME: For now assume that we can't deal with rotation length(unique(xs) == 2) && length(unique(ys) == 2) } } toRectGrobpicComplexPath <- function(x) { lg <- x$children[[2]] xs <- convertX(lg$x[1:4], "native", valueOnly = TRUE) ys <- convertY(lg$y[1:4], "native", valueOnly = TRUE) picRectGrob(x = min(xs), y = min(ys), width = max(xs) - min(xs), height = max(ys) - min(ys), just = c("left", "bottom"), gp = lg$gp, default.units = "native") } stopsToCol <- function(stopStyle) { tmpgp <- gpar(col = stopStyle$`stop-color`, colAlpha = stopStyle$`stop-opacity`) resolveColours(tmpgp)$col } parseTransform <- function(x) { if (is.null(x)) return(x) # Remove "matrix(" and ")" pieces <- strsplit(substring(x, nchar("matrix(") + 1, nchar(x) - 1), ",")[[1]] rbind(matrix(as.numeric(pieces), ncol = 3), c(0, 0, 1)) } .grImport2Env <- new.env() prefixName <- function(name) { paste0(get("prefix", envir = .grImport2Env), name) } generateNewPrefixGen <- function(n = 0) { counter <- n function() { counter <<- counter + 1 paste("import", counter, "", sep = ".") } } generateNewPrefix <- generateNewPrefixGen() setPrefix <- function(prefix = "") { assign("prefix", prefix, envir = .grImport2Env) } updateIdGen <- function() { index <- 0 function(id) { index <<- index + 1 paste(id, "update", index, sep="-") } } updateId <- updateIdGen() grImport2/R/parser.R0000654000176200001440000003347513560672221014000 0ustar liggesusers ################################################################################ ## SVG content is parsed in TWO sweeps: ## 1: definitions (within ) ## 2: other content ## Parsing generates Picture objects ## Sweep 1 creates "definitions" and stores them (by name) in a ## list of definitions. Some elements ONLY do this. ## Sweep 2 creates a big tree of Picture ## objects that represent the image. ## Transformations are applied to Picture objects. ## Some elements NEST (e.g., groups, masks, clipPaths, use), ## in which case, the sweep recursively descends. ## Transformations are applied recursively. ## Some attributes work BY REFERENCE (e.g., mask= and clip-path=), ## in which case, we resolve a LABEL to a Picture definition (in both sweeps). ## elements work by REPLACEMENT, in which case, we retrieve ## a Picture definition. ## Transformations are applied (recursively) to a retrieved definition. ## Transformations generate a new definition, with a new LABEL. ################################################################################ getPictureDims <- function(image) { svgDims <- c(xmlGetAttr(image, "width"), xmlGetAttr(image, "height")) # Remove "pt" as.numeric(substring(svgDims, 1, nchar(svgDims) - 2)) } nullFn <- function(...) { NULL } parseSVGClipPath <- function(x, createDefs) { # Can assume just one child (if necessary) # because Cairo SVG does not include more than # one definition. It's either a rectangle or a path. clipID <- xmlGetAttr(x, "id") # children don't set definitions, set createDefs to FALSE clipRegion <- parseImage(xmlChildren(x, addNames = FALSE), createDefs = FALSE) cp <- new("PictureClipPath", content = clipRegion, label = clipID) if (createDefs) setDef(clipID, cp) # should always be this else cp } parseSVGFeColorMatrix <- function(x, createDefs) { # type will be a matrix # input will be SourceGraphic # primary concern is parsing values, which will likely be the following # sequence of integers: # "0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" nums <- as.integer(strsplit(xmlGetAttr(x, "values"), " ")[[1]]) colmat <- matrix(nums, nrow = 4, ncol = 5, byrow=TRUE) new("PictureFeColorMatrix", type = xmlGetAttr(x, "type"), input = xmlGetAttr(x, "in"), values = colmat) } parseSVGFilter <- function(x, createDefs) { # Can assume just one child (if necessary) # because Cairo SVG does not include more than # a single feColorMatrix element filterID <- xmlGetAttr(x, "id") # children don't set definitions, set createDefs to FALSE fecolmat <- parseImage(xmlChildren(x, addNames = FALSE), createDefs = FALSE)[[1]] f <- new("PictureFilter", filterUnits = "bbox", x = 0, y = 0, width = 1, height = 1, content = fecolmat) if (createDefs) setDef(filterID, f) # should always be this else f } parseSVGGroup <- function(x, createDefs) { # Getting style information to pass on later styleList <- svgStyleToList(xmlGetAttr(x, "style")) if (length(styleList)) { tm <- parseTransform(xmlGetAttr(x, "transform")) gp <- svgStyleListToGpar(styleList) if (! is.null(tm)) gp <- applyTransform(gp, tm) } else { gp <- gpar() } # Just setting defs from children because we do not have # the group as a reference by itself (most likely) if (createDefs && is.null(xmlGetAttr(x, "id"))) return(parseImage(xmlChildren(x, addNames = FALSE), createDefs)) ## children don't set definitions, set createDefs to FALSE children <- do.call("list", parseImage(xmlChildren(x, addNames = FALSE), FALSE)) clippath <- xmlGetAttr(x, "clip-path") clip <- ! is.null(clippath) if (clip) { clipid <- urlToID(clippath) clipRegion <- getDef(clipid) } else { clipRegion <- NULL } pg <- new("PictureGroup", content = children, clip = clipRegion, maskRef = urlToID(xmlGetAttr(x, "mask")), filterRef = urlToID(xmlGetAttr(x, "filter")), gp = gp) if (createDefs && ! is.null(xmlGetAttr(x, "id"))) setDef(xmlGetAttr(x, "id"), pg) else pg } parseSVGImage <- function(x, createDefs) { imageAttrs <- as.list(xmlAttrs(x)) bbox <- c(0, 0, as.numeric(imageAttrs$width), as.numeric(imageAttrs$height)) pimage <- new("PictureImage", x = 0, y = 0, # Always true, as per cairo source width = bbox[3], height = bbox[4], angle = 0, # just initialising image = readBase64Image(imageAttrs$href), maskRef = urlToID(xmlGetAttr(x, "mask")), bbox = bbox) if (createDefs) setDef(imageAttrs$id, pimage) # always the case? else pimage } parseSVGLinearGradient <- function(x, createDefs) { gradAttrs <- as.list(xmlAttrs(x)) spreadMethod <- if (! is.null(gradAttrs$spreadMethod)) gradAttrs$spreadMethod else "pad" stops <- lapply(xmlChildren(x, addNames = FALSE), parseSVGStop, createDefs = FALSE) tm <- parseTransform(gradAttrs$gradientTransform) lg <- new("PictureLinearGradient", x0 = as.numeric(gradAttrs$x1), y0 = as.numeric(gradAttrs$y1), x1 = as.numeric(gradAttrs$x2), y1 = as.numeric(gradAttrs$y2), spreadMethod = spreadMethod, stops = stops) if (! is.null(tm)) lg <- applyTransform(lg, tm) setDef(gradAttrs$id, lg) # can only be setting a def } parseSVGMask <- function(x, createDefs) { maskID <- xmlGetAttr(x, "id") # children don't set definitions, set createDefs to FALSE maskRegion <- parseImage(xmlChildren(x, addNames = FALSE), createDefs = FALSE) m <- new("PictureMask", content = maskRegion) if (createDefs) setDef(maskID, m) # should always be this else m } parseSVGPattern <- function(x, createDefs) { patAttrs <- as.list(xmlAttrs(x)) if (is.null(patAttrs$x)) patAttrs$x <- 0 if (is.null(patAttrs$y)) patAttrs$y <- 0 tm <- parseTransform(patAttrs$patternTransform) children <- parseImage(xmlChildren(x, addNames = FALSE), FALSE) pat <- new("PicturePattern", x = as.numeric(patAttrs$x), y = as.numeric(patAttrs$y), width = as.numeric(patAttrs$width), height = as.numeric(patAttrs$height), angle = 0, # just initialising definition = children) if (! is.null(tm)) { pat <- applyTransform(pat, tm) } setDef(patAttrs$id, pat) # can only be setting a def } parseSVGPath <- function(x, createDefs) { styleList <- svgStyleToList(xmlGetAttr(x, "style")) tm <- parseTransform(xmlGetAttr(x, "transform")) # Sometimes a path is present where d="" d <- xmlGetAttr(x, "d") if (! nzchar(d)) return(NULL) rule <- if (! is.null(styleList$`fill-rule`)) styleList$`fill-rule` else "winding" d <- parsePathData(d) # If path data is (effectively) empty, return NULL if (is.null(d)) return(NULL) gp <- svgStyleListToGpar(styleList) points <- getPoints(d, line = TRUE) p <- new("PicturePath", d = d, rule = rule, gp = gp, bbox = c(min(points$x), max(points$x), min(points$y), max(points$y))) # Scaling path and line data in addition to styling if (! is.null(tm)) { p <- applyTransform(p, tm) } # won't be used by id, so just return p } parseSVGRadialGradient <- function(x, createDefs) { gradAttrs <- as.list(xmlAttrs(x)) spreadMethod <- if (! is.null(gradAttrs$spreadMethod)) gradAttrs$spreadMethod else "pad" stops <- lapply(xmlChildren(x, addNames = FALSE), parseSVGStop, createDefs = FALSE) tm <- parseTransform(gradAttrs$gradientTransform) radgrad <- new("PictureRadialGradient", x = as.numeric(gradAttrs$cx), y = as.numeric(gradAttrs$cy), r = as.numeric(gradAttrs$r), fx = as.numeric(gradAttrs$fx), fy = as.numeric(gradAttrs$fy), spreadMethod = spreadMethod, stops = stops) if (! is.null(tm)) radgrad <- applyTransform(radgrad, tm) setDef(gradAttrs$id, radgrad) # can only be setting a def } parseSVGRect <- function(x, createDefs) { rectAttrs <- as.list(xmlAttrs(x)) styleList <- svgStyleToList(rectAttrs$style) tm <- parseTransform(rectAttrs$transform) gp <- svgStyleListToGpar(styleList) # If 'x' or 'y' are unspecified, # the SVG spec says the value is taken to be zero if (is.null(rectAttrs$x)) rectAttrs$x <- 0 if (is.null(rectAttrs$y)) rectAttrs$y <- 0 xy <- as.numeric(c(rectAttrs$x, rectAttrs$y)) wh <- as.numeric(c(rectAttrs$width, rectAttrs$height)) r <- new("PictureRect", x = xy[1], y = xy[2], width = wh[1], height = wh[2], angle = 0, # just initialising gp = gp, bbox = c(xy, xy + wh)) # Scaling path and line data and gp if (! is.null(tm)) r <- applyTransform(r, tm) # won't be used by id so just return r } parseSVGStop <- function(x, createDefs) { # ignore defs and createalways content for another definition stopAttrs <- as.list(xmlAttrs(x)) offset <- as.numeric(stopAttrs$offset) styleList <- svgStyleToList(stopAttrs$style) col <- stopsToCol(styleList) new("PictureGradientStop", offset = offset, col = col) } parseSVGSymbol <- function(x, createDefs) { symbolID <- xmlGetAttr(x, "id") symbolChildren <- parseImage(xmlChildren(x, addNames = FALSE), createDefs = FALSE) if (is.null(symbolChildren) || ! length(symbolChildren) || is.null(unlist(symbolChildren))) symbolChildren <- list(new("PictureRect", x = 0, y = 0, width = 0, height = 0, angle = 0, gp = gpar(col = "#FFFFFF00", fill = "#FFFFFF00"), bbox = rep(0, 4))) symbol <- new("PictureSymbol", definition = symbolChildren) setDef(symbolID, symbol) } parseSVGUse <- function(x, createDefs) { # Will not be used to set definitions (because a will only # refer to something that already exists, and *not* define anything # new). useAttrs <- as.list(xmlAttrs(x)) def <- getDef(hrefToID(useAttrs$href)) if (is.null(def)) return(NULL) # Assume that the source is not drawable # could spec 'x' and 'y' OR 'transform' (latter for image) # OR possibly neither (in which case provide identity transform) if (is.null(useAttrs$transform)) { if (is.null(useAttrs$x)) tx <- 0 else tx <- as.numeric(useAttrs$x) if (is.null(useAttrs$y)) ty <- 0 else ty <- as.numeric(useAttrs$y) ## No scaling, just translation ## Still need to build up a transformation matrix (for consistency) tm <- diag(3) tm[1, 3] <- tx tm[2, 3] <- ty } else { tm <- parseTransform(useAttrs$transform) } ## Now need to act according to the type of content we have pulled out ## For example, for a , we're only interested in the definition ## and not the itself. ## We'll only be seeing this for symbols and patterns in practice (as ## per the cairo source) if (is(def, "PictureSymbol")) { ## symbol, assume only one child! ## safe because they're only used for font glyphs, which are known ## to be single elements applyTransform(def@definition[[1]], tm) } else if ("maskRef" %in% slotNames(def) && ! is.null(xmlGetAttr(x, "mask"))) { ## Shift mask on to mask on def def@maskRef <- urlToID(xmlGetAttr(x, "mask")) applyTransform(def, tm) } else if (is(def, "PictureImage")) { applyTransform(def, tm) # image } else { applyTransform(def, tm) } } parseImage <- function(x, createDefs = FALSE) { # Ensure there is a list of content to iterate over if (inherits(x, "XMLInternalNode")) x <- list(x) result <- vector("list", length(x)) for (i in seq_len(length(x))) { node <- x[[i]] el <- xmlName(node) ID <- xmlGetAttr(node, "id") svgFn <- switch(el, clipPath = parseSVGClipPath, feColorMatrix = parseSVGFeColorMatrix, filter = parseSVGFilter, g = parseSVGGroup, image = parseSVGImage, linearGradient = parseSVGLinearGradient, mask = parseSVGMask, pattern = parseSVGPattern, path = parseSVGPath, radialGradient = parseSVGRadialGradient, rect = parseSVGRect, symbol = parseSVGSymbol, use = parseSVGUse, nullFn) result[[i]] <- svgFn(node, createDefs) } if (length(result) > 1) result <- result[! sapply(result, is.null)] else result } parsePictureDefinitions <- function(svgImage) { parseImage(getNodeSet(svgImage, "//svg:defs/*", c(svg = "http://www.w3.org/2000/svg")), createDefs = TRUE) } grImport2/R/paths.R0000654000176200001440000001344712231104715013610 0ustar liggesuserssetClass("PathData", representation(segments = "list")) setValidity("PathData", function(object) { all(sapply(object@segments, is, "PathSegment")) }) setClass("PathSegment", representation(x = "numeric", y = "numeric")) setValidity("PathSegment", function(object) length(object@x) == length(object@y)) setClass("PathMoveTo", representation("PathSegment")) setClass("PathLineTo", representation("PathSegment")) setClass("PathCurveTo", representation("PathSegment")) setClass("PathClosePath", representation("PathSegment")) # Convenience constructors moveTo <- function(x, y) new("PathMoveTo", x = x, y = y) lineTo <- function(x, y) new("PathLineTo", x = x, y = y) closePath <- function(x, y) new("PathClosePath", x = x, y = y) curveTo <- function(x, y) { # Perform calculations on an off-screen NULL device pdf(file = NULL) # The unit itself doesn't actually matter, so long as it is absolute xs <- unit(x, "bigpts") ys <- unit(y, "bigpts") points <- bezierPoints(bezierGrob(xs, ys)) ct <- lapply(points, function(x) { convertUnit(x, "bigpts", valueOnly = TRUE) }) dev.off() # close NULL device new("PathCurveTo", x = ct$x, y = ct$y) } # We will need to get the points necessary to create a line or a path. # Create methods used to get these points setGeneric("getPoints", function(object, line) standardGeneric("getPoints")) setMethod("getPoints", signature(object = "PathSegment", line = "logical"), function(object, line) list(x = object@x, y = object@y)) setMethod("getPoints", signature(object = "PathClosePath", line = "logical"), function(object, line) # If we have a path that we're parsing where a closePath is # present, we want to know what the stroke looks like, which is # separate from the fill. # This is because, interestingly, SVG can fill a polyline but # grid (and R graphics) cannot. # This means when we need to draw the stroke for the entire # path we want to know where the stroke ends up, while a fill # does not need to know the final points. if (line) list(x = object@x, y = object@y) else list(x = NULL, y = NULL)) # Now to get points from *all* segments setMethod("getPoints", signature(object = "PathData", line = "logical"), function(object, line) { list(x = unlist(sapply(object@segments, function(ps) getPoints(ps, line)$x)), y = unlist(sapply(object@segments, function(ps) getPoints(ps, line)$y))) }) setMethod("applyTransform", signature(object = "PathData", tm = "matrix"), function(object, tm) { object@segments <- lapply(object@segments, function(pathSegment) { applyTransform(pathSegment, tm) }) object }) setMethod("applyTransform", signature(object = "PathSegment", tm = "matrix"), function(object, tm) { nr <- length(object@x) locs <- matrix(c(object@x, object@y, rep(1, nr)), ncol = 3) for (i in seq_len(nrow(locs))) locs[i, ] <- tm %*% locs[i, ] object@x <- locs[, 1] object@y <- locs[, 2] object }) # Expects to take a string from a 's d="" parsePathData <- function(x) { # Path data comes in the form of "M x y L x y C x y x y x y [Z]" # We want the type, x and y for each command pieces <- strsplit(x, " ")[[1]] # Some paths have d="", just return NULL in that case # because we'll never see anything if (! length(pieces)) return(NULL) # Attempt to cast to numeric # Any that are NA *must* be commands ncommands <- suppressWarnings(length(which(is.na(as.numeric(pieces))))) pathData <- vector("list", length(ncommands)) dataInd <- 0 # Need to maintain a current position (because of curveTo) pos <- numeric(2) # Also start position (for closePath) startPos <- numeric(2) ind <- 1 while (ind <= length(pieces)) { command <- pieces[ind] # Special case to remove trailing "M" command on older # versions of Cairo if (command == "M" && dataInd == (ncommands - 1)) { # BUT watch out for case where path data consist of only # trailing "M" if (ncommands == 1) return(NULL) # Need to truncate list to remove unused command pathData <- pathData[1:dataInd] break } # Regular cases follow if (command == "M") { startPos <- pos <- xy <- as.numeric(pieces[ind + 1:2]) dataInd <- dataInd + 1 pathData[[dataInd]] <- moveTo(xy[1], xy[2]) ind <- ind + 3 } if (command == "L") { pos <- xy <- as.numeric(pieces[ind + 1:2]) dataInd <- dataInd + 1 pathData[[dataInd]] <- lineTo(xy[1], xy[2]) ind <- ind + 3 } if (command == "C") { xy <- as.numeric(pieces[ind + 1:6]) dataInd <- dataInd + 1 pathData[[dataInd]] <- curveTo(c(pos[1], xy[c(TRUE, FALSE)]), c(pos[2], xy[c(FALSE, TRUE)])) pos <- xy[5:6] ind <- ind + 7 } if (command == "Z") { dataInd <- dataInd + 1 pathData[[dataInd]] <- closePath(startPos[1], startPos[2]) ind <- ind + 1 } } new("PathData", segments = pathData) } grImport2/R/grid.picture.R0000654000176200001440000001364413560136147015101 0ustar liggesuserspictureGrob <- function(picture, x = unit(0.5, "npc"), y = unit(0.5, "npc"), width = unit(1, "npc"), height = unit(1, "npc"), just = "centre", hjust = NULL, vjust = NULL, default.units = "npc", expansion = 0.05, xscale = NULL, yscale = NULL, distort = FALSE, gpFUN = identity, ..., ext = c("none", "clipbbox", "gridSVG"), delayContent = match.arg(ext) == "gridSVG", name = NULL, prefix = NULL, clip = "on") { if (delayContent) { if (!is.unit(x)) x <- unit(x, default.units) if (!is.unit(y)) y <- unit(y, default.units) if (!is.unit(width)) width <- unit(width, default.units) if (!is.unit(height)) height <- unit(height, default.units) gTree(picture=picture, x = x, y = y, width = width, height = height, just = just, expansion = expansion, xscale = xscale, yscale = yscale, distort = distort, gpFUN = gpFUN, ext = match.arg(ext), clip = clip, prefix = prefix, grobifyArgs <- list(...), name = name, cl="PictureGrob") } else { if (is.null(prefix)) prefix <- generateNewPrefix() setPrefix(prefix) grobify(picture, x = x, y = y, width = width, height = height, default.units = default.units, just = just, expansion = expansion, xscale = xscale, yscale = yscale, distort = distort, gpFUN = gpFUN, ext = match.arg(ext), clip = clip, ..., name = name) } } makeContent.PictureGrob <- function(x, ...) { if (is.null(x$prefix)) prefix <- generateNewPrefix() else prefix <- x$prefix setPrefix(prefix) picGrob <- do.call(grobify, c(list(x$picture, x = x$x, y = x$y, width = x$width, height = x$height, just = x$just, expansion = x$expansion, xscale = x$xscale, yscale = x$yscale, distort = x$distort, gpFUN = x$gpFUN, ext = x$ext, clip = x$clip), x$grobifyArgs)) setChildren(x, gList(picGrob)) } grid.picture <- function(...) { grid.draw(pictureGrob(...)) } symbolsGrob <- function(picture, x = stats::runif(10), y = stats::runif(10), size = unit(1, "char"), default.units = "native", gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), prefix = NULL, ..., name = NULL) { # Boilerplate for units, ensure that they are vectorised # and indeed proper grid units if (! is.unit(x)) x <- unit(x, default.units) if (! is.unit(y)) y <- unit(y, default.units) if (! is.unit(size)) size <- unit(size, default.units) npics <- max(length(x), length(y), length(size)) x <- rep(x, length.out = npics) y <- rep(y, length.out = npics) size <- rep(size, length.out = npics) ext <- match.arg(ext) # If we have gridSVG, then there is a fast way of drawing everything. # Simply draw a bunch of rectangles and fill them with a pattern. # The pattern definition is the picture itself. if (ext == "gridSVG") { if (! requireNamespace("gridSVG")) stop("gridSVG must be installed to use the 'gridSVG' extension") if (is.null(prefix)) prefix <- generateNewPrefix() widths <- heights <- size rg <- rectGrob(x = x, y = y, width = widths, height = heights, default.units = default.units, name = name, gp = gpar(col = "#FFFFFF00", fill = "#FFFFFF00")) picdef <- pictureGrob(picture, gpFUN = gpFUN, expansion = 0, ext = "gridSVG", prefix = prefix, ...) # Register the "base" pattern that we will later reference. # This ensures that only one definition is ever "drawn", the rest # are just referring to the definition and changing where it is # being used. gridSVG::registerPatternFill(prefix, gridSVG::pattern(picdef, width = 1, height = 1, just = c("left", "bottom"))) for (i in seq_len(npics)) gridSVG::registerPatternFillRef(paste0(prefix, ".", i), prefix, x = x[i], y = y[i], width = widths[i], height = heights[i]) # Because we have registered all of the pattern fill references # we can apply them as a vector of labels (for group = FALSE) gridSVG::patternFillGrob(rg, label = paste0(prefix, ".", seq_len(npics)), group = FALSE) } else { # Slow path, have to redraw the picture multiple times, and without # the use of gridSVG features. # The gridSVG features cannot be used because things like clipping # paths or masks need to be redefined multiple times using multiple # different reference labels. gTree(children = do.call("gList", lapply(seq_len(npics), function(i) { pictureGrob(picture, x = x[i], y = y[i], width = size[i], height = size[i], default.units = default.units, gpFUN = gpFUN, ext = ext, ...) }) )) } } grid.symbols <- function(...) { grid.draw(symbolsGrob(...)) } grImport2/R/grobs.R0000654000176200001440000001551013560662633013614 0ustar liggesusers# Custom grobs that scale their line widths relative the the dimensions # of the image. For example, lines should be thicker when the image is # larger. makeContext.picRect <- function(x) { x$gp <- scaleLwd(x$gp) x } makeContent.picRect <- function(x) { rectGrob(x$x, x$y, x$width, x$height, just = x$just, gp = x$gp, vp=x$vp, name = x$name, default.units = x$default.units) } picRectGrob <- function(x, y, width, height, just, gp, default.units, vp=NULL) { grob(x = x, y = y, width = width, height = height, just = just, gp = gp, default.units = default.units, vp = vp, cl = "picRect") } makeContent.picPath <- function(x) { pathGrob(x$x, x$y, id.lengths = x$id.lengths, rule = x$rule, name = x$name, gp = x$gp, default.units = x$default.units) } picPathGrob <- function(x, y, id.lengths, rule, gp, default.units) { grob(x = x, y = y, id.lengths = id.lengths, rule = rule, gp = gp, default.units = default.units, cl = "picPath") } makeContent.picPolyline <- function(x) { polylineGrob(x$x, x$y, id.lengths = x$id.lengths, name = x$name, gp = x$gp, default.units = x$default.units) } picPolylineGrob <- function(x, y, id.lengths, gp, default.units) { grob(x = x, y = y, id.lengths = id.lengths, gp = gp, default.units = default.units, cl = "picPolyline") } makeContext.picComplexPath <- function(x) { x$gp <- scaleLwd(x$gp) x } picComplexPathGrob <- function(linePoints, pathPoints, lineIDLengths, pathIDLengths, rule, gp) { gTree(children = gList( picPathGrob(unlist(pathPoints$x), unlist(pathPoints$y), id.lengths = pathIDLengths, rule = rule, gp = gpar(col = "#FFFFFF00"), default.units = "native"), picPolylineGrob(unlist(linePoints$x), unlist(linePoints$y), id.lengths = lineIDLengths, gp = gpar(fill = "#FFFFFF00"), default.units = "native") ), gp = gp, cl = "picComplexPath") } scaleLwd <- function(gp) { lwd <- gp$lwd lty <- gp$lty # Calculate the current "resolution" res <- 96 # pdf, png, jpeg, postscript, all 1/96 per lwd scaleFactor <- res * min(abs(convertWidth(unit(1, "native"), "inches", valueOnly = TRUE)), abs(convertHeight(unit(1, "native"), "inches", valueOnly = TRUE))) if (! is.null(lwd)) lwd <- lwd * scaleFactor # FIXME CONSIDER CASE WHEN LWD IS NOT PRESENT if (! is.null(lty)) lty <- paste(as.hexmode(pmax(pmin(round((lty * scaleFactor) / lwd), 15), 1)), collapse = "") gp$lwd <- lwd gp$lty <- lty gp } # Apply gridSVG features to grid grobs # FIXME: Make this more efficient by using registration gridSVGAddFeatures <- function(grob, gp, mask = character(0), filter = character(0)) { gparNames <- names(gp) if ("gradientFill" %in% gparNames) { gradDef <- getDef(gp$gradientFill) if (! is.null(gradDef)) { # Assume a fillAlpha of 1 because there will be no # fill property (due to gradient being there instead) fillAlpha <- 1 grob <- gridSVG::gradientFillGrob(grob, label = prefixName(gp$gradientFill), alpha = fillAlpha) } } if ("gradientStroke" %in% gparNames) { # Do nothing, not supported by gridSVG (yet) #def <- getDef(defs, gp$gradientStroke) } if ("patternFill" %in% gparNames) { patDef <- getDef(gp$patternFill) if (! is.null(patDef)) { fillAlpha <- 1 grob <- gridSVG::patternFillGrob(grob, label = prefixName(gp$patternFill), alpha = fillAlpha) } } if ("patternStroke" %in% gparNames) { # Do nothing, not supported by gridSVG (yet) #def <- getDef(defs, gp$patternStroke) } # Now for masks and filters if (length(mask)) grob <- gridSVG::maskGrob(grob, label = prefixName(mask)) if (length(filter)) grob <- gridSVG::filterGrob(grob, label = prefixName(filter)) grob } # Viewport from picture pictureVP <- function(picture, expansion = 0.05, xscale = NULL, yscale = NULL, distort = FALSE, clip = "on", ...) { if (is.null(xscale) || is.null(yscale)) { xscale <- picture@summary@xscale yscale <- picture@summary@yscale } xscale <- xscale + expansion * c(-1, 1) * diff(xscale) yscale <- yscale + expansion * c(-1, 1) * diff(yscale) # If distort=TRUE, having the two layers of viewports is # massively redundant, BUT I'm keeping it so that either # way there is the same viewport structure, which I think # is beneficial if anyone ever wants to make use of # these viewports (otherwise they would need to figure # out whether a picture grob has one or two viewports). vpStack(viewport(name = "picture.shape", ..., layout = grid.layout(1, 1, widths = abs(diff(xscale)), heights = abs(diff(yscale)), respect = ! distort)), viewport(name = "picture.scale", layout.pos.col = 1, xscale = xscale, yscale = yscale, clip = clip)) } clipVP <- function(xscale, yscale) { # Note: SVG y-scales are reversed viewport(x = xscale[1], y = yscale[2], width = abs(diff(xscale)), height = abs(diff(yscale)), xscale = xscale, yscale = yscale, default.units = "native", just = c("left", "top"), clip = "on") } registerDefs <- function(defs, ext) { content <- defs@content ids <- names(content) for (i in seq_len(length(content))) { def <- content[[i]] label <- prefixName(ids[i]) if (class(def) == "PicturePattern") gridSVG::registerPatternFill(label, grobify(def, ext=ext)) if (class(def) == "PictureFilter") gridSVG::registerFilter(label, grobify(def, ext=ext)) if (class(def) == "PictureMask") gridSVG::registerMask(label, grobify(def, ext=ext)) if (class(def) == "PictureClipPath") gridSVG::registerClipPath(label, gridSVG::clipPath(grobify(def, ext=ext))) if (any(class(def) == c("PictureLinearGradient", "PictureRadialGradient"))) gridSVG::registerGradientFill(label, grobify(def, ext=ext)) } } grImport2/R/import.R0000654000176200001440000000564313566616754014031 0ustar liggesusersreadPicture <- function(file, warn = TRUE, initDefs = TRUE) { if (missing(file)) stop("'file' must be a character string representing a path to a file.") doc <- xmlParse(file) checkValidSVG(doc, warn = warn) svgImage <- xmlRoot(doc) pictureDims <- getPictureDims(svgImage) ## Initialise defs in .grImport2Env so can be modded on-the-fly ## during parseImage if (initDefs) { assign("defs", new("PictureDefinitions"), envir=.grImport2Env) } # Fill up picture definitions table first parsePictureDefinitions(svgImage) # Now parse the contents of the image ( are ignored). # s are resolved to "real" elements pic <- parseImage(xmlChildren(svgImage, addNames = FALSE), createDefs = FALSE) # Update defs for changes during parseImage picdefs <- get("defs", envir=.grImport2Env) new("Picture", content = pic, defs = picdefs, summary = new("PictureSummary", xscale = c(0, pictureDims[1]), yscale = c(pictureDims[2], 0))) } checkValidSVG <- function(doc, minVersion = NA, warn = TRUE) { if (xmlName(xmlRoot(doc)) != "svg") stop("This picture is not an SVG document.") if (! warn) return() # Note: suppressing warnings because we know we just want comments # and do not care about the namespace (SVG) that they belong in comments <- suppressWarnings(getNodeSet(doc, "//comment()")) grConvertSVG <- length(comments) && grepl("Created by grConvert", xmlValue(comments[[1]])) if (grConvertSVG) { cairoSVG <- TRUE ## Future proofing on grConvert input, add a min version check on ## the output that grConvert creates. if (! is.na(minVersion)) { grConvertComment <- xmlValue(grConvertComment[[1]]) ## Collect the version number (of the form v0.1-0, for example) fileVersion <- gsub(".*v([0-9.-]+) $", "\\1", grConvertComment, perl = TRUE) if (package_version(fileVersion) < package_version(minVersion)) warning(paste0("This picture was generated by an old version ", " of 'grConvert'. ", "The minimum supported version is ", minVersion,". Errors may result")) } } else { topGroup <- getNodeSet(doc, "/svg:svg/svg:g[1]", namespaces=c(svg="http://www.w3.org/2000/svg")) if (length(topGroup)) { groupAttrs <- xmlAttrs(topGroup[[1]]) } else { groupAttrs <- NULL } cairoSVG <- length(groupAttrs) && "id" %in% names(groupAttrs) && grepl("^surface", groupAttrs["id"]) } if (!cairoSVG) { warningText <- "This picture was not generated by Cairo graphics; errors may result" warning(warningText) } } grImport2/R/grobify.R0000654000176200001440000004035413562647726014155 0ustar liggesuserssetMethod("grobify", signature(object = "PictureClipPath"), function(object, defs, gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), ...) { ext <- match.arg(ext) if (is.null(object@content) || ! length(object@content)) return(gTree()) children <- lapply(object@content, grobify, defs = defs, gpFUN = gpFUN, ext = ext) gTree(children = do.call("gList", children)) }) setMethod("grobify", signature(object = "PictureFeColorMatrix"), function(object) { gridSVG::feColorMatrix(input = object@input, type = object@type, values = object@values) }) setMethod("grobify", signature(object = "PictureFilter"), function(object, ...) { # defs are not needed, nor gpFUN, and gridSVG is implied gridSVG::filterEffect(grobify(object@content), filterUnits = object@filterUnits, x = object@x, y = object@y, width = object@width, height = object@height, just = c("left", "bottom")) }) setMethod("grobify", signature(object = "PictureMask"), function(object, defs, gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), ...) { ext <- match.arg(ext) if (is.null(object@content) || ! length(object@content)) return(gridSVG::mask(gTree())) children <- lapply(object@content, grobify, defs = defs, gpFUN = gpFUN, ext = ext) gridSVG::mask(gTree(children = do.call("gList", children))) }) setMethod("grobify", signature(object = "PicturePattern"), function(object, ext = c("none", "clipbbox", "gridSVG"), ...) { ext <- match.arg(ext) # Ignoring gpFUN because it will only be applied to a # raster and gp settings do not apply to rasters. # dims in inches # We need this because the device needs to be only as large # as the pattern (as parsed by grImport), no more. win <- abs(convertWidth(unit(object@width, "native"), "inches", valueOnly = TRUE)) hin <- abs(convertHeight(unit(object@height, "native"), "inches", valueOnly = TRUE)) # Grobify all pattern content patternContent <- lapply(object@definition, grobify, ext=ext, ...) # Construct bounding box for pattern # bbox <- getbbox(object@definition) bbox <- c(0, abs(object@width), 0, abs(object@height)) # Generate gTree containing all content # AND with viewport that has scale based on content bbox tilegrob <- gTree(children=do.call("gList", patternContent), vp=viewport(xscale=bbox[1:2], yscale=bbox[3:4])) # Draw a pattern. # The pattern has some dimensions, but these dimensions # must be matched by the width of the pattern tile device. gridSVG::pattern(tilegrob, x = object@x, y = object@y, width = object@width, height = object@height, default.units = "native", just = c("left", "bottom"), dev.width = win, dev.height = hin) }) setMethod("grobify", signature(object = "PictureImage"), function(object, ext = c("none", "clipbbox", "gridSVG"), ...) { ext <- match.arg(ext) # Note gpFUN is not used here because it has no effect on # rasterGrobs. The 'grid' documentation points out that all # gpar settings are *ignored*. # IF the PictureImage has an angle, we need to generate # a viewport to draw the raster within (to perform the rotation) if (!length(object@angle)) object@angle <- 0 if (object@angle != 0) { r <- rasterGrob(object@image, x=0, y=1, width=1, height=-1, just=c("left", "bottom"), vp = angleVP(object, image=TRUE)) } else { r <- rasterGrob(object@image, x = object@x, y = object@y + object@height, width = object@width, height = -object@height, default.units = "native", just = c("left", "bottom")) } # Note, could add gridSVG features but we know only masks # can be applied to an if (ext == "gridSVG" && length(object@maskRef) && length(object@maskRef)) gridSVG::maskGrob(r, label = prefixName(object@maskRef)) else r }) setMethod("grobify", signature(object = "PictureRadialGradient"), function(object, ...) { stops <- lapply(object@stops, grobify) offsets <- sapply(stops, function(x) x$offset) cols <- sapply(stops, function(x) x$col) gridSVG::radialGradient(col = cols, stops = offsets, gradientUnits = "coords", x = object@x, y = object@y, r = object@r, fx = object@fx, fy = object@fy, spreadMethod = object@spreadMethod, default.units = "native") }) setMethod("grobify", signature(object = "PictureLinearGradient"), function(object, ...) { stops <- lapply(object@stops, grobify) offsets <- sapply(stops, function(x) x$offset) cols <- sapply(stops, function(x) x$col) gridSVG::linearGradient(col = cols, stops = offsets, gradientUnits = "coords", x0 = object@x0, x1 = object@x1, y0 = object@y0, y1 = object@y1, spreadMethod = object@spreadMethod, default.units = "native") }) setMethod("grobify", signature(object = "PictureGradientStop"), function(object, ...) { list(offset = object@offset, col = object@col) }) # Only called when we already know object@transform is non-NULL angleVP <- function(object, image=FALSE) { # Get new x, y, width, height, and angle from # original x, y, width, height, and transform if (image) { object@angle <- -object@angle } viewport(x = object@x, y = object@y, width = object@width, height = object@height, just = c("left", "bottom"), default.units = "native", angle = 180 * object@angle / pi, name = "anglevp") } setMethod("grobify", signature(object = "PictureRect"), function(object, defs, gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), ...) { ext <- match.arg(ext) object@gp <- gpFUN(object@gp) # IF the PictureRect has an angle, we need to generate # a viewport to draw the rect within (to perform the rotation) if (!length(object@angle)) object@angle <- 0 if (object@angle != 0) { grob <- picRectGrob(.5, .5, 1, 1, "centre", object@gp, "npc", vp = angleVP(object)) } else { grob <- picRectGrob(object@x, object@y, object@width, object@height, just = c("left", "bottom"), default.units = "native", gp = object@gp) } if (ext == "gridSVG") grob <- gridSVGAddFeatures(grob, object@gp) grob }) setMethod("grobify", signature(object = "PicturePath"), function(object, defs, gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), ...) { ext <- match.arg(ext) # Due to the complex nature of SVG paths, we require a bit # of calculation in order to translate these into R paths. ismt <- sapply(object@d@segments, is, "PathMoveTo") nsp <- sum(ismt) # number of subpaths, always at least 1 starts <- which(ismt) groupSize <- diff(c(starts, length(ismt) + 1)) ngroups <- length(groupSize) # Lines should have fewer points than a path (when there # are close paths present linePoints <- getPoints(object@d, line = TRUE) pathPoints <- getPoints(object@d, line = FALSE) if (ngroups == 1) { # No need to split into sub-grobs because we only have # a single region to consider pidlen <- lidlen <- NULL } else { # Complex case where we need to consider how the sub-grobs # are split into different groups. Collecting the lengths # of each sub-grob group pidlen <- lidlen <- numeric(ngroups) for (i in seq_len(ngroups)) { groupInds <- starts[i] + 0:(groupSize[i] - 1) lidlen[i] <- sum(sapply(object@d@segments[groupInds], function(x) { length(getPoints(x, line = TRUE)$x) })) pidlen[i] <- sum(sapply(object@d@segments[groupInds], function(x) { length(getPoints(x, line = FALSE)$x) })) # If pidlen is less than lidlen *and* pidlen is only # length 1 this means that the path data is simply a # MOVETO and a CLOSEPATH. In other words, this subpath # does nothing. # Just assume that we have a LINETO instead (which draws # no line), this makes things a bit easier than removing. # This is because the subpath will still match the # associated polyline fragment. Furthermore, it means # that when exporting via gridSVG, the sub-grob ID # is a bit more sensible (because it is not removing an # empty group). if (pidlen[i] < lidlen[i] && pidlen[i] == 1) { # i == 1 is a simple append case if (i == 1) { pathPoints$x <- c(pathPoints$x[1], pathPoints$x) pathPoints$y <- c(pathPoints$y[1], pathPoints$y) } else { # last position plus one (current) pos <- sum(pidlen[1:(i - 1)]) pathPoints$x <- append(pathPoints$x, pathPoints$x[pos], after = pos) pathPoints$y <- append(pathPoints$y, pathPoints$y[pos], after = pos) } # We now have two points, so use that pidlen[i] <- 2 } } } object@gp <- gpFUN(object@gp) # Create a complex path grob. # The complication with this grob arises due to the fact that # SVG s can have a fill region, whereas the R (and # therefore grid) graphics engine cannot. # A polyline draws the stroke, while a path draws the fill # region of the *SVG* path. # This produces the same effect when the stroke is drawn above # the filled path (which picComplexPathGrob attempts to ensure) grob <- picComplexPathGrob(linePoints, pathPoints, lidlen, pidlen, object@rule, object@gp) if (ext == "gridSVG") grob <- gridSVGAddFeatures(grob, object@gp) grob }) setMethod("grobify", signature(object = "PictureGroup"), function(object, defs, gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), ...) { ext <- match.arg(ext) clipvp <- if (! is.null(object@clip) && ext == "clipbbox") { cp <- object@clip bbox <- getbbox(cp) clipVP(bbox[1:2], bbox[3:4]) } else { NULL } object@gp <- gpFUN(object@gp) childTree <- lapply(object@content, grobify, defs = defs, gpFUN = gpFUN, ext = ext) groupGrob <- gTree(children = do.call("gList", childTree), gp = object@gp, vp = clipvp) if (! is.null(object@clip) && ext == "gridSVG") { cp <- object@clip groupGrob <- gridSVG::clipPathGrob(groupGrob, label = prefixName(cp@label)) } if (ext == "gridSVG") groupGrob <- gridSVGAddFeatures(groupGrob, object@gp, object@maskRef, object@filterRef) groupGrob }) setMethod("grobify", signature(object = "Picture"), function(object, gpFUN = identity, ext = c("none", "clipbbox", "gridSVG"), expansion = 0.05, xscale = NULL, yscale = NULL, distort = FALSE, clip = "on", name = NULL, ...) { ext <- match.arg(ext) pvp <- pictureVP(object, expansion = expansion, xscale = xscale, yscale = yscale, distort = distort, clip = clip, ...) if (ext == "gridSVG") { if (! requireNamespace("gridSVG")) { warning("the 'gridSVG' package is required for advanced graphical features, reverting to 'clipbbox'") ext <- "clipbbox" } else { # Things like gradients and patterns need to be aware of # native scales at the time of registration. Because of # this we also set the gradient and pattern labels to be # the same as the SVG IDs. pushViewport(pvp, recording = FALSE) registerDefs(object@defs, ext) # Up 2 because we pushed a vpStack of 2 viewports upViewport(2, recording = FALSE) } } children <- lapply(object@content, grobify, defs = object@defs, gpFUN = gpFUN, ext = ext) gt <- gTree(children = do.call("gList", children), name = name, vp = pvp) gt$name <- prefixName(gt$name) gt }) grImport2/MD50000644000176200001440000000670713567034712012471 0ustar liggesusersea3a049c6d2cc1fa9c9a295e9dd6b3d0 *DESCRIPTION 597a41ce2d27c2338513b6039ef156be *NAMESPACE 5ca827a51b292bd433bc99ee225bbca6 *R/classes.R 0e737f5974e7c1a18491e35c08d957b0 *R/grid.picture.R 6c31bc07b749c59b08f35de0a194b79d *R/grobify.R 69258a3d63d292fffcbb9601581d6509 *R/grobs.R ace3aee2b9c46992817bb67dc3b4e086 *R/import.R ff335c3027455ae37000f3850f2e46b2 *R/parser.R 0e6417456dc4b62a0e8f7fc9357214a0 *R/paths.R 310e1e0fa575853e5a1320dfd6949d0c *R/utils.R 53d20971a700503f04ca2c32c591c60d *inst/NEWS.Rd 13cd768d41362ee43cee08cca2686421 *inst/SVG/lwd-rsvg.svg f9c06128b32b141a3556f76c8770c04e *inst/SVG/lwd.svg d2979cf81a41e886eb988312631e6305 *man/PathClosePath-class.Rd 9920d107368ce8a6d5f4542ed654e04e *man/PathCurveTo-class.Rd 2fcd8e16da1f4c6da8a0c5a464082772 *man/PathData-class.Rd 2ed25ee8105d718c04cdbab42f266f0c *man/PathLineTo-class.Rd 01660c823ae7ef63a09e658ecacb2610 *man/PathMoveTo-class.Rd 2f7656a800437d3d6bdfe0cc51030c8b *man/PathSegment-class.Rd 40ddc066db14e1d6022f0d600bb45026 *man/Picture-class.Rd 216229ee053e5653e9bd2e08ba6bb44a *man/PictureClipPath-class.Rd 22543b9e7ecd14552520656c5aa42024 *man/PictureContent-class.Rd 9c2e34ed6d61471bba051b300d028159 *man/PictureDefinitions-class.Rd 8b16b76ad11a31a7401e0b4f5d3ff83c *man/PictureFeColorMatrix-class.Rd 26b2acce49843a79cc3a4e16be347f67 *man/PictureFilter-class.Rd 8ad1bcfef165b5a7504a57764efe5f1a *man/PictureGradientStop-class.Rd a49584e248eebc04c5af0b888e45371c *man/PictureGroup-class.Rd af1c0dc9d1d97d8d1093df415921179e *man/PictureImage-class.Rd 397591f63095ec8e238dd2d226d448a2 *man/PictureLinearGradient-class.Rd 13e281a551a347f0de87438fb65ebd51 *man/PictureMask-class.Rd dd07070931920646f51c011834abdd57 *man/PicturePath-class.Rd 6a51e285e1fef20150543980f8ed9d29 *man/PicturePattern-class.Rd e740beb69e208f3c810583013922f830 *man/PictureRadialGradient-class.Rd 7286505ff5c537ae8aa6135815d45da5 *man/PictureRect-class.Rd 281adb40762dfe7fc9623e52db630f15 *man/PictureSummary-class.Rd 6d306b0bc30d89be89bcfafdb6731b7e *man/PictureSymbol-class.Rd d2da3e588e725abb648d809a5fa8f806 *man/applyTransform-gpar.Rd 630044765b71c6b5f865791025b9c769 *man/applyTransform.Rd 69e51b075a75fad765dbbf51dda8864a *man/grid.picture.Rd 76339a818d303bcd7062ba6713576d5f *man/grid.symbols.Rd 4f69e7a3ddd92d393f0e56db2adcfef0 *man/grobify.Rd 518762077c5544e263a5f08db8d3b296 *man/paths.Rd f40d5c341c25dfd4e1998597ed75d6d0 *man/readPicture.Rd 92e0b0445ecd543f56477508b663da31 *tests/test-bboxclip-output.svg.save b8568babfdfd65f5eb77465f877a1ca5 *tests/test-clip-input.svg edb39d3ed32730af28419d8bb7d249cc *tests/test-clip.R 5710cd2db225f92ee36302d4d6932d04 *tests/test-noclip-output.svg.save 093f1bb2e5ae8ffb5e2ccfbd9ccaf824 *tests/test-path-complex-input.svg 306722baa7449da726e053e62f7ff908 *tests/test-path-complex-output.svg.save 4644664d9c2e1b5201222a0c5a5a1ef8 *tests/test-path-simple-input.svg e60e218f752f5cd23b3f87b87748b099 *tests/test-path-simple-output.svg.save 3ffbc35ea5f3b3152144488ca1e1ad47 *tests/test-paths.R f3b6dc84652426f02709280c44d0d2b6 *tests/test-raster-input.svg d7d1505fda716965e5dea913e461432f *tests/test-raster-output.svg.save f02aa4f4120af754b8b6e01e6d8faee3 *tests/test-raster.R 64cc1b59bdd673f9827b09c302a61e0b *tests/test-rect-input.svg 0f05c9b0fde9eefc5315e96166dcb125 *tests/test-rect-output.svg.save e78ac463d3374c42914cd056147c7317 *tests/test-rect.R c9ac19d8a58bc4a742970c49c139bc72 *tests/test-symbol-input.svg 3c2c053f4479838830e81d642d208873 *tests/test-symbol-output.svg.save 839a34f7e0ec71cb23e12600abdd3961 *tests/test-symbol.R grImport2/inst/0000755000176200001440000000000013252321674013121 5ustar liggesusersgrImport2/inst/SVG/0000755000176200001440000000000013252323163013553 5ustar liggesusersgrImport2/inst/SVG/lwd.svg0000654000176200001440000000117513252321711015064 0ustar liggesusers grImport2/inst/SVG/lwd-rsvg.svg0000654000176200001440000000232013252323163016037 0ustar liggesusers grImport2/inst/NEWS.Rd0000654000176200001440000001117613566617763014212 0ustar liggesusers\name{NEWS} \title{NEWS file for the grImport2 package} \encoding{UTF-8} \section{Changes in version 0.2-0}{ \itemize{ \item \code{pictureGrob()} has a new argument \code{delayContent}. If that is \code{TRUE}, the function returns a \code{"PictureGrob"} gTree that has a \code{makeContent()} method, so that \code{grobify()} only happens at drawing time, so that, IF we are using \pkg{gridSVG} for output, registration of SVG definitions happens within the current viewport. The default value is \code{ext == "gridSVG"}. \item Internal restructuring: to fix more complex SVG input where \code{} refer to each other and include nested transformations; to handle transformations more consistently in general; to fix calculation of bounding box for transformed clipping path. \item \code{readPicture()} has a new argument \code{initDefs}, which controls whether the list of definitions (things like masks, filters, gradient fills, ...) is initialized when reading a new picture. This should be set to \code{FALSE} when importing and drawing more than one picture in the same R image. } } \section{Changes in version 0.1-6}{ \itemize{ \item fix for importing SVG containing \code{} elements that refer to complex content (including nested \code{} elements, \code{} use elements with \code{transform} attributes, \code{} elements with \code{mask} attributes, and \code{use} content with \code{clip-path} attributes. \item fix for feColorMatrix filter (matrix value was being transposed). \item fix for \code{ext="gridSVG"} when exporting definitions (like masks) that contain references to other definitions (like filters). } } \section{Changes in version 0.1-5}{ \itemize{ \item Added \code{clip} argument to \code{grid.picture()} so that we can inherit clipping region when drawing an imported image (default remains that the picture sets its own clipping viewport). Thanks to Silas Dean. } } \section{Changes in version 0.1-4}{ \itemize{ \item Fix for importing radial gradient with gradientTransform (radius of gradient was not being transformed correctly). } } \section{Changes in version 0.1-3}{ \itemize{ \item Fix for \code{makeContent()} methods for picRect, picPath, and picPolyline, so that the forced grob has the same name as the original grob. \item Fix for parsing \code{} element with no children or with empty image. \item Fix for import of \code{lwd} from SVG \code{line-width} \item Relax import requirement that SVG file be generated by \pkg{grConvert}; now accept SVG file that is generated by \pkg{grConvert} OR SVG file that can be identified as being generated by Cairo graphics. This allows us to accept, for example, files generated by \code{rsvg_svg()} from the \pkg{rsvg} package. } } \section{Changes in version 0.1-2}{ \itemize{ \item Fix for importing rotated rectangles. \item Fix for importing rotated raster images. \item Improved import of line widths. \item Enhancement of importing patterns to allow general pattern content, rather than just a single image as pattern content. } } \section{Changes in version 0.1-1}{ \itemize{ \item Fix for 'default.units' argument in grid.picture(), which was being ignored. \item Fix to grobify() method for \code{"PictureImage"} to correct location calculation for raster element (was doing incorrect unit arithmetic). \item Fix to parseSVGUse() to handle direct of image (not for a pattern or mask, but for an actual image); problem was that image was not positioned correctly. \item Fix to pictureVP() to handle inverted x-scale or y-scale; problem was evident in incorrect overall clipping (because pictureVP() was incorrect shape). \item Fix to path parsing to handle path data of the form \code{d="M x y"} (by ignoring such paths). \item Bug fix for converting SVG style to gpar settings when style is a url() reference (it was doing the wrong thing to replace, for example, \code{gp$fill} with \code{gp$gradientFill} and could end up with neither). \item Bug fix for with 'transform' and 'fill' that is url() reference. The transform was not being applied to the referenced gradient fill. } } \section{Changes in version 0.1-0}{ \itemize{ \item Initial release. Intended to import SVG images generated by the 'grConvert' package. \item Now using SVG instead of PostScript, allowing us to support many more graphical features. } }