├── configure.win ├── src ├── .gitignore ├── Makevars.ucrt ├── tests │ └── sysdeps.c ├── Makevars.in ├── Makevars.win ├── gdtools.cpp ├── versions.cpp ├── font_metrics.cpp ├── CairoContext.cpp ├── raster_to_base64.cpp └── RcppExports.cpp ├── inst └── include │ ├── gdtools_types.cpp │ ├── gdtools.h │ ├── gdtools_types.h │ └── gdtools_RcppExports.h ├── cleanup ├── tests ├── testthat.R └── testthat │ ├── helper-fontconfig.R │ ├── test-str_metrics.R │ ├── test-raster.R │ └── test-str_extents.R ├── .gitignore ├── .Rbuildignore ├── man ├── sys_fonts.Rd ├── version_cairo.Rd ├── fontconfig_reinit.Rd ├── set_dummy_conf.Rd ├── font_family_exists.Rd ├── match_family.Rd ├── str_metrics.Rd ├── glyphs_match.Rd ├── raster_write.Rd ├── str_extents.Rd ├── raster_str.Rd └── m_str_extents.Rd ├── tools └── winlibs.R ├── gdtools.Rproj ├── R ├── font_family_exists.R ├── gdtools.R ├── fontconfig.R ├── m_str_extents.R ├── cpp-proxies.R ├── raster.R └── RcppExports.R ├── NAMESPACE ├── DESCRIPTION ├── cran-comments.md ├── .github └── workflows │ └── R-CMD-check.yaml ├── NEWS ├── README.md ├── README.Rmd ├── configure └── LICENSE /configure.win: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | Makevars 2 | -------------------------------------------------------------------------------- /inst/include/gdtools_types.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -f src/Makevars configure.log 3 | -------------------------------------------------------------------------------- /src/Makevars.ucrt: -------------------------------------------------------------------------------- 1 | CRT=-ucrt 2 | include Makevars.win 3 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(gdtools) 3 | 4 | test_check("gdtools") 5 | -------------------------------------------------------------------------------- /src/tests/sysdeps.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main () { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /tests/testthat/helper-fontconfig.R: -------------------------------------------------------------------------------- 1 | 2 | local <- function() { 3 | identical(Sys.getenv("NOT_CRAN"), "true") 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/Makevars.in: -------------------------------------------------------------------------------- 1 | PKG_CPPFLAGS=@cflags@ -I../inst/include/ 2 | PKG_CXXFLAGS=$(C_VISIBILITY) 3 | PKG_LIBS=@libs@ 4 | 5 | all: clean 6 | 7 | clean: 8 | rm -f $(SHLIB) $(OBJECTS) 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | src/*.o 5 | src/*.so 6 | src/*.dll 7 | ^.*\.Rproj$ 8 | config.status 9 | windows 10 | inst/doc 11 | revdep 12 | configure.log 13 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^gdtools\.Rproj$ 4 | ^src/Makevars$ 5 | ^cran-comments\.md$ 6 | ^windows 7 | ^revdep$ 8 | ^README\.Rmd$ 9 | ^configure.log$ 10 | ^\.github$ 11 | -------------------------------------------------------------------------------- /inst/include/gdtools.h: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #ifndef RCPP_gdtools_H_GEN_ 5 | #define RCPP_gdtools_H_GEN_ 6 | 7 | #include "gdtools_RcppExports.h" 8 | 9 | #endif // RCPP_gdtools_H_GEN_ 10 | -------------------------------------------------------------------------------- /man/sys_fonts.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fontconfig.R 3 | \name{sys_fonts} 4 | \alias{sys_fonts} 5 | \title{List system fonts.} 6 | \usage{ 7 | sys_fonts() 8 | } 9 | \description{ 10 | List system fonts details into a data.frame containing columns foundry, family, 11 | file, slant and weight. 12 | } 13 | \examples{ 14 | sys_fonts() 15 | } 16 | -------------------------------------------------------------------------------- /tools/winlibs.R: -------------------------------------------------------------------------------- 1 | VERSION <- commandArgs(TRUE) 2 | if(!file.exists(sprintf("../windows/cairo-%s/include/cairo/cairo.h", VERSION))){ 3 | if(getRversion() < "3.3.0") setInternet2() 4 | download.file(sprintf("https://github.com/rwinlib/cairo/archive/v%s.zip", VERSION), "lib.zip", quiet = TRUE) 5 | dir.create("../windows", showWarnings = FALSE) 6 | unzip("lib.zip", exdir = "../windows") 7 | unlink("lib.zip") 8 | } 9 | -------------------------------------------------------------------------------- /tests/testthat/test-str_metrics.R: -------------------------------------------------------------------------------- 1 | context("font file metric info") 2 | 3 | 4 | test_that("a string has positive dimensions", { 5 | skip_if_not_installed("fontquiver") 6 | file <- fontquiver::font("Bitstream Vera", "Sans", "Bold")$ttf 7 | value <- str_metrics(x = "Hello World", fontsize = 12, fontfile = file ) 8 | expect_true( value["width"] > 0) 9 | expect_true( value["ascent"] > 0 ) 10 | expect_false( value["descent"] < 0 ) 11 | }) 12 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | VERSION = 1.16.0 2 | RWINLIB = ../windows/cairo-${VERSION} 3 | 4 | PKG_CPPFLAGS = -I${RWINLIB}/include/cairo -I${RWINLIB}/include \ 5 | -I${RWINLIB}/include/freetype2 -I../inst/include 6 | 7 | PKG_LIBS = -L${RWINLIB}/lib${R_ARCH}${CRT} -lcairo -lfreetype -lpng -lpixman-1 \ 8 | -lharfbuzz -lbz2 -lz -liconv -lgdi32 9 | 10 | all: winlibs 11 | 12 | winlibs: 13 | "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" ${VERSION} 14 | -------------------------------------------------------------------------------- /gdtools.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /man/version_cairo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/RcppExports.R, R/gdtools.R 3 | \name{version_freetype} 4 | \alias{version_freetype} 5 | \alias{version_cairo} 6 | \title{Version numbers of C libraries} 7 | \usage{ 8 | version_freetype() 9 | 10 | version_cairo() 11 | } 12 | \description{ 13 | \code{version_cairo()} and \code{version_freetype()} return the 14 | runtime version. These helpers return version objects as with 15 | \code{\link[utils]{packageVersion}()}. 16 | } 17 | -------------------------------------------------------------------------------- /man/fontconfig_reinit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fontconfig.R 3 | \name{fontconfig_reinit} 4 | \alias{fontconfig_reinit} 5 | \title{reload Fontconfig configuration} 6 | \usage{ 7 | fontconfig_reinit() 8 | } 9 | \description{ 10 | This function can be used to make fontconfig 11 | reload font configuration files. 12 | } 13 | \note{ 14 | Fontconfig is not used anymore and that function will be deprecated 15 | in the next release. 16 | } 17 | \author{ 18 | Paul Murrell 19 | } 20 | -------------------------------------------------------------------------------- /tests/testthat/test-raster.R: -------------------------------------------------------------------------------- 1 | context("raster") 2 | 3 | test_that("raster_str", { 4 | r <- as.raster(matrix(hcl(0, 80, seq(40, 80, 10)), nrow = 5, ncol = 4)) 5 | code <- raster_str(r, width = 50, height = 50) 6 | expect_gt(nchar(x = code), 50) 7 | }) 8 | 9 | test_that("raster_write", { 10 | r <- as.raster(matrix(hcl(0, 80, seq(40, 80, 10)), nrow = 5, ncol = 4)) 11 | filename <- tempfile(fileext = ".png") 12 | raster_write(r, path = filename, width = 50, height = 50) 13 | expect_true(file.exists(filename)) 14 | }) 15 | -------------------------------------------------------------------------------- /man/set_dummy_conf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fontconfig.R 3 | \name{set_dummy_conf} 4 | \alias{set_dummy_conf} 5 | \alias{unset_dummy_conf} 6 | \title{Set and unset a minimalistic Fontconfig configuration} 7 | \usage{ 8 | set_dummy_conf() 9 | 10 | unset_dummy_conf() 11 | } 12 | \description{ 13 | Set and unset a minimalistic Fontconfig configuration 14 | } 15 | \note{ 16 | Fontconfig is not used anymore and these functions will be deprecated 17 | in the next release. 18 | } 19 | -------------------------------------------------------------------------------- /R/font_family_exists.R: -------------------------------------------------------------------------------- 1 | #' @title Check if font family exists. 2 | #' 3 | #' @description Check if a font family exists in system fonts. 4 | #' 5 | #' @return A logical value 6 | #' @param font_family font family name (case sensitive) 7 | #' @examples 8 | #' font_family_exists("sans") 9 | #' font_family_exists("Arial") 10 | #' font_family_exists("Courier") 11 | #' @export 12 | #' @importFrom systemfonts match_font system_fonts 13 | font_family_exists <- function( font_family = "sans" ){ 14 | datafonts <- system_fonts() 15 | tolower(font_family) %in% tolower(datafonts$family) 16 | } 17 | -------------------------------------------------------------------------------- /man/font_family_exists.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/font_family_exists.R 3 | \name{font_family_exists} 4 | \alias{font_family_exists} 5 | \title{Check if font family exists.} 6 | \usage{ 7 | font_family_exists(font_family = "sans") 8 | } 9 | \arguments{ 10 | \item{font_family}{font family name (case sensitive)} 11 | } 12 | \value{ 13 | A logical value 14 | } 15 | \description{ 16 | Check if a font family exists in system fonts. 17 | } 18 | \examples{ 19 | font_family_exists("sans") 20 | font_family_exists("Arial") 21 | font_family_exists("Courier") 22 | } 23 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(font_family_exists) 4 | export(fontconfig_reinit) 5 | export(glyphs_match) 6 | export(m_str_extents) 7 | export(match_family) 8 | export(raster_str) 9 | export(raster_view) 10 | export(raster_write) 11 | export(set_dummy_conf) 12 | export(str_extents) 13 | export(str_metrics) 14 | export(sys_fonts) 15 | export(unset_dummy_conf) 16 | export(version_cairo) 17 | export(version_freetype) 18 | importFrom(Rcpp,sourceCpp) 19 | importFrom(grDevices,is.raster) 20 | importFrom(systemfonts,match_font) 21 | importFrom(systemfonts,system_fonts) 22 | useDynLib(gdtools) 23 | -------------------------------------------------------------------------------- /R/gdtools.R: -------------------------------------------------------------------------------- 1 | #' @useDynLib gdtools 2 | #' @importFrom Rcpp sourceCpp 3 | #' @importFrom grDevices is.raster 4 | NULL 5 | 6 | #' Version numbers of C libraries 7 | #' 8 | #' \code{version_cairo()} and \code{version_freetype()} return the 9 | #' runtime version. These helpers return version objects as with 10 | #' \code{\link[utils]{packageVersion}()}. 11 | #' @export 12 | version_cairo <- function() { 13 | ver <- version_cairo_() 14 | ver <- strsplit(ver, "\\.")[[1]] 15 | ver <- as.integer(ver) 16 | 17 | structure(list(ver), class = c("package_version", "numeric_version")) 18 | } 19 | #' @importFrom systemfonts match_font 20 | -------------------------------------------------------------------------------- /man/match_family.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fontconfig.R 3 | \name{match_family} 4 | \alias{match_family} 5 | \title{Find best family match with systemfonts} 6 | \usage{ 7 | match_family(font = "sans", bold = TRUE, italic = TRUE, debug = NULL) 8 | } 9 | \arguments{ 10 | \item{font}{family or face to match.} 11 | 12 | \item{bold}{Wheter to match a font featuring a \code{bold} face.} 13 | 14 | \item{italic}{Wheter to match a font featuring an \code{italic} face.} 15 | 16 | \item{debug}{deprecated} 17 | } 18 | \description{ 19 | \code{match_family()} returns the best font family match. 20 | } 21 | \examples{ 22 | match_family("sans") 23 | match_family("serif") 24 | } 25 | -------------------------------------------------------------------------------- /man/str_metrics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cpp-proxies.R 3 | \name{str_metrics} 4 | \alias{str_metrics} 5 | \title{Get font metrics for a string.} 6 | \usage{ 7 | str_metrics( 8 | x, 9 | fontname = "sans", 10 | fontsize = 12, 11 | bold = FALSE, 12 | italic = FALSE, 13 | fontfile = "" 14 | ) 15 | } 16 | \arguments{ 17 | \item{x}{Character vector of strings to measure} 18 | 19 | \item{fontname}{Font name} 20 | 21 | \item{fontsize}{Font size} 22 | 23 | \item{bold}{Is text bold/italic?} 24 | 25 | \item{italic}{Is text bold/italic?} 26 | 27 | \item{fontfile}{Font file} 28 | } 29 | \value{ 30 | A named numeric vector 31 | } 32 | \description{ 33 | Get font metrics for a string. 34 | } 35 | \examples{ 36 | str_metrics("Hello World!") 37 | } 38 | -------------------------------------------------------------------------------- /src/gdtools.cpp: -------------------------------------------------------------------------------- 1 | #include "gdtools_types.h" 2 | #include 3 | 4 | using namespace Rcpp; 5 | // [[Rcpp::interfaces(r, cpp)]] 6 | 7 | // [[Rcpp::export]] 8 | XPtrCairoContext context_create() { 9 | return XPtrCairoContext(new CairoContext()); 10 | } 11 | 12 | // [[Rcpp::export]] 13 | bool context_set_font(XPtrCairoContext cc, std::string fontname, 14 | double fontsize, bool bold, bool italic, 15 | std::string fontfile = "") { 16 | cc->setFont(fontname, fontsize, bold, italic, fontfile); 17 | 18 | // should return void, but doesn't seem to be supported for cpp 19 | // interface 20 | return true; 21 | } 22 | 23 | // [[Rcpp::export]] 24 | FontMetric context_extents(XPtrCairoContext cc, std::string x) { 25 | return cc->getExtents(x); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /man/glyphs_match.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cpp-proxies.R 3 | \name{glyphs_match} 4 | \alias{glyphs_match} 5 | \title{Validate glyph entries} 6 | \usage{ 7 | glyphs_match(x, fontname = "sans", bold = FALSE, italic = FALSE, fontfile = "") 8 | } 9 | \arguments{ 10 | \item{x}{Character vector of strings} 11 | 12 | \item{fontname}{Font name} 13 | 14 | \item{bold, italic}{Is text bold/italic?} 15 | 16 | \item{fontfile}{Font file} 17 | } 18 | \value{ 19 | a logical vector, if a character element is containing at least 20 | a glyph that can not be matched in the font table, FALSE is returned. 21 | } 22 | \description{ 23 | Determines if strings contain glyphs not part of a font. 24 | } 25 | \examples{ 26 | glyphs_match(letters) 27 | glyphs_match("\u265E", bold = TRUE) 28 | } 29 | -------------------------------------------------------------------------------- /man/raster_write.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/raster.R 3 | \name{raster_write} 4 | \alias{raster_write} 5 | \title{Draw/preview a raster to a png file} 6 | \usage{ 7 | raster_write(x, path, width = 480, height = 480, interpolate = FALSE) 8 | } 9 | \arguments{ 10 | \item{x}{A raster object} 11 | 12 | \item{path}{name of the file to create} 13 | 14 | \item{width, height}{Width and height in pixels.} 15 | 16 | \item{interpolate}{A logical value indicating whether to linearly 17 | interpolate the image.} 18 | } 19 | \description{ 20 | Draw/preview a raster to a png file 21 | } 22 | \examples{ 23 | r <- as.raster(matrix(hcl(0, 80, seq(50, 80, 10)), 24 | nrow = 4, ncol = 5)) 25 | filepng <- tempfile(fileext = ".png") 26 | raster_write(x = r, path = filepng, width = 50, height = 50) 27 | } 28 | -------------------------------------------------------------------------------- /man/str_extents.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cpp-proxies.R 3 | \name{str_extents} 4 | \alias{str_extents} 5 | \title{Compute string extents.} 6 | \usage{ 7 | str_extents( 8 | x, 9 | fontname = "sans", 10 | fontsize = 12, 11 | bold = FALSE, 12 | italic = FALSE, 13 | fontfile = "" 14 | ) 15 | } 16 | \arguments{ 17 | \item{x}{Character vector of strings to measure} 18 | 19 | \item{fontname}{Font name} 20 | 21 | \item{fontsize}{Font size} 22 | 23 | \item{bold, italic}{Is text bold/italic?} 24 | 25 | \item{fontfile}{Font file} 26 | } 27 | \description{ 28 | Determines the width and height of a bounding box that's big enough 29 | to (just) enclose the provided text. 30 | } 31 | \examples{ 32 | str_extents(letters) 33 | str_extents("Hello World!", bold = TRUE, italic = FALSE, 34 | fontname = "sans", fontsize = 12) 35 | } 36 | -------------------------------------------------------------------------------- /man/raster_str.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/raster.R 3 | \name{raster_str} 4 | \alias{raster_str} 5 | \alias{raster_view} 6 | \title{Draw/preview a raster into a string} 7 | \usage{ 8 | raster_str(x, width = 480, height = 480, interpolate = FALSE) 9 | 10 | raster_view(code) 11 | } 12 | \arguments{ 13 | \item{x}{A raster object} 14 | 15 | \item{width, height}{Width and height in pixels.} 16 | 17 | \item{interpolate}{A logical value indicating whether to linearly 18 | interpolate the image.} 19 | 20 | \item{code}{base64 code of a raster} 21 | } 22 | \description{ 23 | \code{raster_view} is a helper function for testing. It uses \code{htmltools} 24 | to render a png as an image with base64 encoded data image. 25 | } 26 | \examples{ 27 | r <- as.raster(matrix(hcl(0, 80, seq(50, 80, 10)), 28 | nrow = 4, ncol = 5)) 29 | code <- raster_str(r, width = 50, height = 50) 30 | if (interactive() && require("htmltools")) { 31 | raster_view(code = code) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: gdtools 2 | Version: 0.2.3.9000 3 | License: GPL-3 | file LICENSE 4 | Title: Utilities for Graphical Rendering 5 | Description: Useful tools for writing vector graphics devices. 6 | Authors@R: c( 7 | person("David", "Gohel", , "david.gohel@ardata.fr", c("aut", "cre")), 8 | person("Hadley", "Wickham", , "hadley@rstudio.com", "aut"), 9 | person("Lionel", "Henry", , "lionel@rstudio.com", "aut"), 10 | person("Jeroen", "Ooms", role = "aut", email = "jeroen@berkeley.edu", 11 | comment = c(ORCID = "0000-0002-4035-0289")), 12 | person("Yixuan", "Qiu", role = "ctb"), 13 | person("R Core Team", role = "cph", comment = "Cairo code from X11 device"), 14 | person("RStudio", role = "cph") 15 | ) 16 | Imports: 17 | Rcpp (>= 0.12.12), 18 | systemfonts (>= 0.1.1) 19 | Suggests: 20 | htmltools, 21 | testthat, 22 | fontquiver (>= 0.2.0), 23 | curl 24 | Encoding: UTF-8 25 | LinkingTo: Rcpp 26 | SystemRequirements: cairo, freetype2, fontconfig 27 | BugReports: https://github.com/davidgohel/gdtools/issues 28 | RoxygenNote: 7.1.1 29 | -------------------------------------------------------------------------------- /src/versions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include FT_FREETYPE_H 4 | #include 5 | 6 | Rcpp::List version_make(int major, int minor, int patch) { 7 | Rcpp::IntegerVector version; 8 | Rcpp::CharacterVector s3_class; 9 | version = Rcpp::IntegerVector::create(major, minor, patch); 10 | s3_class = Rcpp::CharacterVector::create("package_version", "numeric_version"); 11 | 12 | Rcpp::List output; 13 | output = Rcpp::List::create(version); 14 | output.attr("class") = s3_class; 15 | 16 | return output; 17 | } 18 | 19 | //' @rdname version_cairo 20 | //' @export 21 | // [[Rcpp::export]] 22 | Rcpp::List version_freetype() { 23 | FT_Library library; 24 | if (FT_Init_FreeType(&library)) 25 | Rcpp::stop("FreeType error: unable to initialise library"); 26 | 27 | int major, minor, patch = 0; 28 | FT_Library_Version(library, &major, &minor, &patch); 29 | FT_Done_FreeType(library); 30 | 31 | return version_make(major, minor, patch); 32 | } 33 | 34 | // [[Rcpp::export]] 35 | Rcpp::CharacterVector version_cairo_() { 36 | return cairo_version_string(); 37 | } 38 | -------------------------------------------------------------------------------- /tests/testthat/test-str_extents.R: -------------------------------------------------------------------------------- 1 | context("metric info") 2 | 3 | test_that("a string has positive dimensions", { 4 | value <- str_extents("Hello World!") 5 | expect_true(all( value > 0 )) 6 | }) 7 | 8 | extents <- function(font, ...) { 9 | extents <- str_extents("foobar", fontfile = font$ttf, ...) 10 | as.vector(round(extents, 4)) 11 | } 12 | 13 | 14 | test_that("known fonts have correct metrics", { 15 | skip_if_not_installed("fontquiver") 16 | sans <- fontquiver::font("Liberation", "Sans", "Regular") 17 | mono_bi <- fontquiver::font("Bitstream Vera", "Sans Mono", "Bold Oblique") 18 | expect_equal(extents(sans), c(34.0254, 8.8281), tolerance = .1) 19 | expect_equal(extents(mono_bi), c(43.3477, 9.2969), tolerance = .1) 20 | }) 21 | 22 | test_that("fractional font sizes are correctly measured", { 23 | skip_if_not_installed("fontquiver") 24 | sans <- fontquiver::font("Liberation", "Sans", "Regular") 25 | if (version_freetype() < "2.6.0") { 26 | skip("Old FreeType return different extents for fractional sizes") 27 | } 28 | expect_equal(extents(sans, fontsize = 15.05), c(42.5317, 11.0156), tolerance = .2) 29 | }) 30 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Test environments 2 | 3 | - local OS X install (R 4.0.2) 4 | - ubuntu 16.04 (release) 5 | - macOS (release and devel) 6 | - winbuilder (with release and devel) 7 | 8 | ## R CMD check results 9 | 10 | There were no ERROR, WARNING or NOTE. 11 | 12 | ## Reverse dependencies 13 | 14 | There were 0 ERROR, 0 WARNING and 0 NOTE related to gdtools. 15 | 16 | customLayout 0.3.1 ── E: 1 | W: 0 | N: 0 17 | flextable 0.6.1 ── E: 0 | W: 0 | N: 0 18 | ggdist 2.4.0 ── E: 0 | W: 0 | N: 0 19 | ggiraph 0.7.8 ── E: 0 | W: 0 | N: 0 20 | hrbrthemes 0.8.0 ── E: 0 | W: 0 | N: 0 21 | JuniperKernel 1.4.1.0 ── E: 0 | W: 0 | N: 1 22 | naniar 0.6.0 ── E: 0 | W: 0 | N: 0 23 | svglite 1.2.3.2 ── E: 0 | W: 0 | N: 0 24 | rvg 0.2.5 ── E: 0 | W: 0 | N: 0 25 | tidybayes 2.3.1 ── E: 0 | W: 0 | N: 0 26 | vdiffr 0.3.3 ── E: 0 | W: 0 | N: 1 27 | tsmp 0.4.14 ── E: 0 | W: 0 | N: 2 28 | visdat 0.5.3 ── E: 0 | W: 0 | N: 0 29 | -------------------------------------------------------------------------------- /man/m_str_extents.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/m_str_extents.R 3 | \name{m_str_extents} 4 | \alias{m_str_extents} 5 | \title{Compute string extents for a vector of string.} 6 | \usage{ 7 | m_str_extents( 8 | x, 9 | fontname = "sans", 10 | fontsize = 10, 11 | bold = FALSE, 12 | italic = FALSE, 13 | fontfile = NULL 14 | ) 15 | } 16 | \arguments{ 17 | \item{x}{Character vector of strings to measure} 18 | 19 | \item{fontname}{Font name. A vector of character to match with x.} 20 | 21 | \item{fontsize}{Font size. A vector of numeric to match with x.} 22 | 23 | \item{bold, italic}{Is text bold/italic?. A vector of logical to match with x.} 24 | 25 | \item{fontfile}{Font file. A vector of character to match with x.} 26 | } 27 | \description{ 28 | For each \code{x} element, determines the width and height of a bounding box that's big enough 29 | to (just) enclose the provided text. Unit is pixel. 30 | } 31 | \examples{ 32 | \donttest{ 33 | # The first run can be slow when font caches are missing 34 | # as font files are then being scanned to build those font caches. 35 | m_str_extents(letters, fontsize = 1:26) 36 | m_str_extents(letters[1:3], 37 | bold = c(TRUE, FALSE, TRUE), 38 | italic = c(FALSE, TRUE, TRUE), 39 | fontname = c("sans", "sans", "sans") ) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /R/fontconfig.R: -------------------------------------------------------------------------------- 1 | #' @title List system fonts. 2 | #' 3 | #' @description List system fonts details into a data.frame containing columns foundry, family, 4 | #' file, slant and weight. 5 | #' 6 | #' @examples 7 | #' sys_fonts() 8 | #' @export 9 | sys_fonts <- function() { 10 | system_fonts() 11 | } 12 | 13 | #' Find best family match with systemfonts 14 | #' 15 | #' \code{match_family()} returns the best font family match. 16 | #' 17 | #' @param font family or face to match. 18 | #' @param bold Wheter to match a font featuring a \code{bold} face. 19 | #' @param italic Wheter to match a font featuring an \code{italic} face. 20 | #' @param debug deprecated 21 | #' @export 22 | #' @examples 23 | #' match_family("sans") 24 | #' match_family("serif") 25 | #' @importFrom systemfonts match_font system_fonts 26 | match_family <- function(font = "sans", bold = TRUE, italic = TRUE, debug = NULL) { 27 | font <- match_font(font, bold = bold, italic = italic) 28 | sysfonts <- system_fonts() 29 | match <- which( sysfonts$path %in% font$path ) 30 | sysfonts$family[match[1]] 31 | } 32 | 33 | 34 | #' Set and unset a minimalistic Fontconfig configuration 35 | #' 36 | #' @note 37 | #' Fontconfig is not used anymore and these functions will be deprecated 38 | #' in the next release. 39 | #' @export 40 | set_dummy_conf <- function() { 41 | } 42 | 43 | #' @rdname set_dummy_conf 44 | #' @export 45 | unset_dummy_conf <- function() { 46 | } 47 | 48 | #' @export 49 | #' @title reload Fontconfig configuration 50 | #' @description This function can be used to make fontconfig 51 | #' reload font configuration files. 52 | #' @note 53 | #' Fontconfig is not used anymore and that function will be deprecated 54 | #' in the next release. 55 | #' @author Paul Murrell 56 | fontconfig_reinit <- function() { 57 | } 58 | -------------------------------------------------------------------------------- /R/m_str_extents.R: -------------------------------------------------------------------------------- 1 | #' Compute string extents for a vector of string. 2 | #' 3 | #' For each \code{x} element, determines the width and height of a bounding box that's big enough 4 | #' to (just) enclose the provided text. Unit is pixel. 5 | #' @param x Character vector of strings to measure 6 | #' @param bold,italic Is text bold/italic?. A vector of logical to match with x. 7 | #' @param fontname Font name. A vector of character to match with x. 8 | #' @param fontsize Font size. A vector of numeric to match with x. 9 | #' @param fontfile Font file. A vector of character to match with x. 10 | #' @examples 11 | #' \donttest{ 12 | #' # The first run can be slow when font caches are missing 13 | #' # as font files are then being scanned to build those font caches. 14 | #' m_str_extents(letters, fontsize = 1:26) 15 | #' m_str_extents(letters[1:3], 16 | #' bold = c(TRUE, FALSE, TRUE), 17 | #' italic = c(FALSE, TRUE, TRUE), 18 | #' fontname = c("sans", "sans", "sans") ) 19 | #' } 20 | #' @export 21 | m_str_extents <- function(x, fontname = "sans", fontsize=10, bold = FALSE, italic = FALSE, fontfile = NULL) { 22 | 23 | stopifnot(is.character(x), is.character(fontname), 24 | is.numeric(fontsize), is.logical(bold), 25 | is.logical(italic), is.character(fontfile) || is.null(fontfile)) 26 | 27 | max_length <- length(x) 28 | fontname <- rep(fontname, length.out = max_length) 29 | fontsize <- rep(fontsize, length.out = max_length) 30 | bold <- rep(bold, length.out = max_length) 31 | italic <- rep(italic, length.out = max_length) 32 | 33 | if( is.null(fontfile) ) 34 | fontfile <- rep("", length.out = max_length) 35 | else 36 | fontfile <- rep(fontfile, length.out = max_length) 37 | 38 | m_str_extents_(x, fontname, fontsize, bold, italic, fontfile) 39 | } 40 | -------------------------------------------------------------------------------- /inst/include/gdtools_types.h: -------------------------------------------------------------------------------- 1 | #ifndef __GDTOOLS_TYPES__ 2 | #define __GDTOOLS_TYPES__ 3 | 4 | #include 5 | 6 | class FontMetric { 7 | public: 8 | double height, width, ascent, descent; 9 | 10 | FontMetric(); 11 | FontMetric(SEXP); 12 | operator SEXP() const ; 13 | }; 14 | 15 | #include 16 | using namespace Rcpp; 17 | 18 | inline FontMetric::FontMetric() {} 19 | 20 | inline FontMetric::FontMetric(SEXP x_) { 21 | Rcpp::NumericVector x(x_); 22 | if (x.size() != 4) 23 | Rcpp::stop("Invalid size"); 24 | 25 | width = x[0]; 26 | height = x[1]; 27 | ascent = x[2]; 28 | descent = x[3]; 29 | } 30 | 31 | inline FontMetric::operator SEXP() const { 32 | return Rcpp::NumericVector::create(width, height, ascent, descent); 33 | } 34 | 35 | typedef struct _cairo_font_face cairo_font_face_t; 36 | 37 | class CairoContext { 38 | struct CairoContext_; 39 | CairoContext_* cairo_; 40 | typedef std::map fontCache; 41 | 42 | public: 43 | CairoContext(); 44 | ~CairoContext(); 45 | 46 | void cacheFont(fontCache& cache, std::string& key, std::string fontfile, int fontindex); 47 | void cacheSystemFont(std::string& key, std::string& fontname, bool bold, bool italic); 48 | void setFont(std::string fontname = "sans", double fontsize = 12, 49 | bool bold = false, bool italic = false, 50 | std::string fontfile = ""); 51 | void setUserFont(std::string& fontname, double fontsize, 52 | bool bold, bool italic, std::string& fontfile); 53 | void setSystemFont(std::string& fontname, double fontsize, 54 | bool bold, bool italic); 55 | 56 | FontMetric getExtents(std::string x); 57 | bool validateGlyphs(std::string x); 58 | 59 | }; 60 | 61 | typedef Rcpp::XPtr XPtrCairoContext; 62 | 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /R/cpp-proxies.R: -------------------------------------------------------------------------------- 1 | #' Compute string extents. 2 | #' 3 | #' Determines the width and height of a bounding box that's big enough 4 | #' to (just) enclose the provided text. 5 | #' 6 | #' @param x Character vector of strings to measure 7 | #' @param bold,italic Is text bold/italic? 8 | #' @param fontname Font name 9 | #' @param fontsize Font size 10 | #' @param fontfile Font file 11 | #' @examples 12 | #' str_extents(letters) 13 | #' str_extents("Hello World!", bold = TRUE, italic = FALSE, 14 | #' fontname = "sans", fontsize = 12) 15 | #' @export 16 | str_extents <- function(x, fontname = "sans", fontsize = 12, bold = FALSE, italic = FALSE, fontfile = "") { 17 | str_extents_(x = x, fontname = fontname, fontsize = fontsize, bold = bold, italic = italic, fontfile = fontfile) 18 | } 19 | 20 | #' Get font metrics for a string. 21 | #' 22 | #' @return A named numeric vector 23 | #' @inheritParams str_extents 24 | #' @examples 25 | #' str_metrics("Hello World!") 26 | #' @export 27 | str_metrics <- function(x, fontname = "sans", fontsize = 12, bold = FALSE, italic = FALSE, fontfile = "") { 28 | str_metrics_(x = x, fontname = fontname, fontsize = fontsize, bold = bold, italic = italic, fontfile = fontfile) 29 | } 30 | 31 | #' Validate glyph entries 32 | #' 33 | #' Determines if strings contain glyphs not part of a font. 34 | #' 35 | #' @param x Character vector of strings 36 | #' @param bold,italic Is text bold/italic? 37 | #' @param fontname Font name 38 | #' @param fontfile Font file 39 | #' @return a logical vector, if a character element is containing at least 40 | #' a glyph that can not be matched in the font table, FALSE is returned. 41 | #' 42 | #' @examples 43 | #' glyphs_match(letters) 44 | #' glyphs_match("\u265E", bold = TRUE) 45 | #' @export 46 | glyphs_match <- function(x, fontname = "sans", bold = FALSE, italic = FALSE, fontfile = "") { 47 | glyphs_match_(x = x, fontname = fontname, bold = bold, italic = italic, fontfile = fontfile) 48 | } 49 | -------------------------------------------------------------------------------- /R/raster.R: -------------------------------------------------------------------------------- 1 | #' Draw/preview a raster into a string 2 | #' 3 | #' \code{raster_view} is a helper function for testing. It uses \code{htmltools} 4 | #' to render a png as an image with base64 encoded data image. 5 | #' 6 | #' @param x A raster object 7 | #' @param width,height Width and height in pixels. 8 | #' @param interpolate A logical value indicating whether to linearly 9 | #' interpolate the image. 10 | #' @param code base64 code of a raster 11 | #' @export 12 | #' @examples 13 | #' r <- as.raster(matrix(hcl(0, 80, seq(50, 80, 10)), 14 | #' nrow = 4, ncol = 5)) 15 | #' code <- raster_str(r, width = 50, height = 50) 16 | #' if (interactive() && require("htmltools")) { 17 | #' raster_view(code = code) 18 | #' } 19 | raster_str <- function(x, width = 480, height = 480, interpolate = FALSE) { 20 | 21 | stopifnot(is.raster(x)) 22 | 23 | value <- base64_raster_encode(x, 24 | w = ncol(x), h = nrow(x), width = width, height = height, 25 | interpolate = interpolate) 26 | value 27 | } 28 | 29 | 30 | #' @export 31 | #' @rdname raster_str 32 | raster_view <- function(code) { 33 | img <- paste0("") 34 | htmltools::browsable(htmltools::HTML(img)) 35 | } 36 | 37 | 38 | 39 | 40 | #' Draw/preview a raster to a png file 41 | #' 42 | #' @param x A raster object 43 | #' @param path name of the file to create 44 | #' @param width,height Width and height in pixels. 45 | #' @param interpolate A logical value indicating whether to linearly 46 | #' interpolate the image. 47 | #' @export 48 | #' @examples 49 | #' r <- as.raster(matrix(hcl(0, 80, seq(50, 80, 10)), 50 | #' nrow = 4, ncol = 5)) 51 | #' filepng <- tempfile(fileext = ".png") 52 | #' raster_write(x = r, path = filepng, width = 50, height = 50) 53 | raster_write <- function(x, path, width = 480, height = 480, 54 | interpolate = FALSE) { 55 | stopifnot(is.raster(x)) 56 | 57 | raster_png_(raster_ = x, 58 | w = ncol(x), h = nrow(x), 59 | width = as.double(width), height = as.double(height), 60 | interpolate = interpolate, 61 | filename = path) 62 | 63 | invisible(path) 64 | } 65 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | str_extents_ <- function(x, fontname = "sans", fontsize = 12, bold = FALSE, italic = FALSE, fontfile = "") { 5 | .Call('_gdtools_str_extents_', PACKAGE = 'gdtools', x, fontname, fontsize, bold, italic, fontfile) 6 | } 7 | 8 | str_metrics_ <- function(x, fontname = "sans", fontsize = 12, bold = FALSE, italic = FALSE, fontfile = "") { 9 | .Call('_gdtools_str_metrics_', PACKAGE = 'gdtools', x, fontname, fontsize, bold, italic, fontfile) 10 | } 11 | 12 | m_str_extents_ <- function(x, fontname, fontsize, bold, italic, fontfile) { 13 | .Call('_gdtools_m_str_extents_', PACKAGE = 'gdtools', x, fontname, fontsize, bold, italic, fontfile) 14 | } 15 | 16 | glyphs_match_ <- function(x, fontname = "sans", bold = FALSE, italic = FALSE, fontfile = "") { 17 | .Call('_gdtools_glyphs_match_', PACKAGE = 'gdtools', x, fontname, bold, italic, fontfile) 18 | } 19 | 20 | context_create <- function() { 21 | .Call('_gdtools_context_create', PACKAGE = 'gdtools') 22 | } 23 | 24 | context_set_font <- function(cc, fontname, fontsize, bold, italic, fontfile = "") { 25 | .Call('_gdtools_context_set_font', PACKAGE = 'gdtools', cc, fontname, fontsize, bold, italic, fontfile) 26 | } 27 | 28 | context_extents <- function(cc, x) { 29 | .Call('_gdtools_context_extents', PACKAGE = 'gdtools', cc, x) 30 | } 31 | 32 | raster_to_str <- function(raster, w, h, width, height, interpolate) { 33 | .Call('_gdtools_raster_to_str', PACKAGE = 'gdtools', raster, w, h, width, height, interpolate) 34 | } 35 | 36 | raster_to_file <- function(raster, w, h, width, height, interpolate, filename) { 37 | .Call('_gdtools_raster_to_file', PACKAGE = 'gdtools', raster, w, h, width, height, interpolate, filename) 38 | } 39 | 40 | raster_png_ <- function(raster_, w, h, width, height, interpolate, filename) { 41 | .Call('_gdtools_raster_png_', PACKAGE = 'gdtools', raster_, w, h, width, height, interpolate, filename) 42 | } 43 | 44 | base64_raster_encode <- function(raster_, w, h, width, height, interpolate) { 45 | .Call('_gdtools_base64_raster_encode', PACKAGE = 'gdtools', raster_, w, h, width, height, interpolate) 46 | } 47 | 48 | base64_file_encode <- function(filename) { 49 | .Call('_gdtools_base64_file_encode', PACKAGE = 'gdtools', filename) 50 | } 51 | 52 | base64_string_encode <- function(string) { 53 | .Call('_gdtools_base64_string_encode', PACKAGE = 'gdtools', string) 54 | } 55 | 56 | #' @rdname version_cairo 57 | #' @export 58 | version_freetype <- function() { 59 | .Call('_gdtools_version_freetype', PACKAGE = 'gdtools') 60 | } 61 | 62 | version_cairo_ <- function() { 63 | .Call('_gdtools_version_cairo_', PACKAGE = 'gdtools') 64 | } 65 | 66 | # Register entry points for exported C++ functions 67 | methods::setLoadAction(function(ns) { 68 | .Call('_gdtools_RcppExport_registerCCallable', PACKAGE = 'gdtools') 69 | }) 70 | -------------------------------------------------------------------------------- /src/font_metrics.cpp: -------------------------------------------------------------------------------- 1 | #include "gdtools_types.h" 2 | #include 3 | #include 4 | 5 | using namespace Rcpp; 6 | 7 | // [[Rcpp::export]] 8 | NumericMatrix str_extents_(CharacterVector x, std::string fontname = "sans", 9 | double fontsize = 12, int bold = false, 10 | int italic = false, std::string fontfile = "") { 11 | int n = x.size(); 12 | CairoContext cc; 13 | cc.setFont(fontname, fontsize, bold, italic, fontfile); 14 | NumericMatrix out(n, 2); 15 | 16 | for (int i = 0; i < n; ++i) { 17 | if (x[i] == NA_STRING) { 18 | out(i, 0) = NA_REAL; 19 | out(i, 1) = NA_REAL; 20 | } else { 21 | std::string str(Rf_translateCharUTF8(x[i])); 22 | FontMetric fm = cc.getExtents(str); 23 | 24 | out(i, 0) = fm.width; 25 | out(i, 1) = fm.height; 26 | } 27 | } 28 | 29 | return out; 30 | } 31 | 32 | // [[Rcpp::export]] 33 | NumericVector str_metrics_(CharacterVector x, std::string fontname = "sans", 34 | double fontsize = 12, int bold = false, 35 | int italic = false, std::string fontfile = "") { 36 | 37 | CairoContext cc; 38 | cc.setFont(fontname, fontsize, bold, italic, fontfile); 39 | 40 | std::string str(Rf_translateCharUTF8(x[0])); 41 | 42 | FontMetric fm = cc.getExtents(str); 43 | 44 | return NumericVector::create( 45 | _["width"] = fm.width, 46 | _["ascent"] = fm.ascent, 47 | _["descent"] = fm.descent 48 | ); 49 | } 50 | 51 | // [[Rcpp::export]] 52 | NumericMatrix m_str_extents_(CharacterVector x, 53 | std::vector fontname, 54 | std::vector fontsize, 55 | std::vector bold, 56 | std::vector italic, 57 | std::vector fontfile) { 58 | int n = x.size(); 59 | CairoContext cc; 60 | NumericMatrix out(n, 2); 61 | 62 | for (int i = 0; i < n; ++i) { 63 | cc.setFont(fontname[i], fontsize[i], bold[i], italic[i], fontfile[i]); 64 | if (x[i] == NA_STRING) { 65 | out(i, 0) = NA_REAL; 66 | out(i, 1) = NA_REAL; 67 | } else { 68 | std::string str(Rf_translateCharUTF8(x[i])); 69 | FontMetric fm = cc.getExtents(str); 70 | 71 | out(i, 0) = fm.width; 72 | out(i, 1) = fm.height; 73 | } 74 | } 75 | 76 | return out; 77 | } 78 | 79 | // [[Rcpp::export]] 80 | LogicalVector glyphs_match_(CharacterVector x, std::string fontname = "sans", 81 | int bold = false, int italic = false, 82 | std::string fontfile = "") { 83 | int n = x.size(); 84 | CairoContext cc; 85 | cc.setFont(fontname, 10.0, bold, italic, fontfile); 86 | LogicalVector out(n); 87 | 88 | for (int i = 0; i < n; ++i) { 89 | if (x[i] == NA_STRING) { 90 | out(i) = NA_LOGICAL; 91 | } else { 92 | std::string str(Rf_translateCharUTF8(x[i])); 93 | out(i) = cc.validateGlyphs(str); 94 | } 95 | } 96 | 97 | return out; 98 | } 99 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: 6 | branches: 7 | - master 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | if: "!contains(github.event.head_commit.message, 'ci skip')" 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: windows-latest, r: 'devel'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: macOS-latest, r: 'release'} 24 | - {os: macOS-latest, r: 'devel'} 25 | - {os: ubuntu-16.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"} 26 | 27 | env: 28 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true 29 | RSPM: ${{ matrix.config.rspm }} 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - uses: r-lib/actions/setup-r@master 35 | with: 36 | r-version: ${{ matrix.config.r }} 37 | 38 | - uses: r-lib/actions/setup-pandoc@master 39 | 40 | - name: install freetype2 and imagemagick deps 41 | if: matrix.config.os == 'macOS-latest' 42 | run: | 43 | brew install fontconfig cairo freetype2 44 | 45 | - name: Query dependencies 46 | run: | 47 | install.packages('remotes') 48 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) 49 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") 50 | shell: Rscript {0} 51 | 52 | - name: Cache R packages 53 | if: runner.os != 'Windows' 54 | uses: actions/cache@v1 55 | with: 56 | path: ${{ env.R_LIBS_USER }} 57 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} 58 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- 59 | 60 | - name: Install system dependencies 61 | if: runner.os == 'Linux' 62 | env: 63 | RHUB_PLATFORM: linux-x86_64-ubuntu-gcc 64 | run: | 65 | Rscript -e "remotes::install_github('r-hub/sysreqs')" 66 | sysreqs=$(Rscript -e "cat(sysreqs::sysreq_commands('DESCRIPTION'))") 67 | sudo -s eval "$sysreqs" 68 | 69 | - name: Install dependencies 70 | run: | 71 | remotes::install_deps(dependencies = TRUE) 72 | remotes::install_cran("rcmdcheck") 73 | shell: Rscript {0} 74 | 75 | - name: Check 76 | env: 77 | _R_CHECK_CRAN_INCOMING_REMOTE_: false 78 | run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") 79 | shell: Rscript {0} 80 | 81 | - name: Upload check results 82 | if: failure() 83 | uses: actions/upload-artifact@master 84 | with: 85 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results 86 | path: check 87 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | # gdtools 0.2.4 2 | 3 | * Windows: add support for ucrt toolchains 4 | 5 | # gdtools 0.2.3 6 | 7 | * fixes for configure script for M1 mac and solaris 8 | 9 | # gdtools 0.2.2 10 | 11 | * Small tweaks for configure script 12 | 13 | # gdtools 0.2.1 14 | 15 | ## issues 16 | 17 | * Change font_family_exists so that it only check a family exists in 18 | family column returned by systemfonts::system_fonts() 19 | * fix a memory leak 20 | 21 | # gdtools 0.2.0 22 | 23 | * refactor - package is now using package systemfonts instead of using fontconfig to locate fonts file 24 | 25 | # gdtools 0.1.9 26 | 27 | * keep locale intact when using various gdtools functions (fix #51) 28 | * Reuse magick FONTCONFIG_PATH if exists 29 | 30 | # gdtools 0.1.8 31 | 32 | * Windows: update cairo stack to rwinlib/cairo v1.15.10 33 | 34 | # gdtools 0.1.6 35 | 36 | * update with Rcpp 0.12.12 37 | * new function `glyphs_match` to test whether glyphs in strings are all existing in a font table or not. 38 | 39 | # gdtools 0.1.5 40 | 41 | * increase tolerance in font metrics unit-tests as new version of freetype 42 | is slightly changing returned extents. 43 | 44 | # gdtools 0.1.4 45 | 46 | * New file src/registerDynamicSymbol.c to correctly register provided routines 47 | * a cleanup file to delete src/Makevars when package has been built 48 | 49 | # gdtools 0.1.3 50 | 51 | * Add set_dummy_conf() and unset_dummy_conf() to set a minimalistic 52 | Fontconfig configuration. Useful to speed up cache building on 53 | Appveyor or CRAN. 54 | * skip tests that need fontquiver when not installed. 55 | 56 | # gdtools 0.1.2 57 | 58 | * Fix a crash on some Linux platforms (hadley/svglite#80) 59 | 60 | # gdtools 0.1.1 61 | 62 | ## updates 63 | 64 | * examples from sys_fonts and match_family are marked as donttest as their first run 65 | can be slow if no font caches are existing. 66 | 67 | # gdtools 0.1.0 68 | 69 | ## new functions 70 | 71 | * sys_fonts: get system fonts details. 72 | * font_family_exists: test if a given font family name can be matched exactly 73 | * match_family: find best family match for a given Fontconfig pattern 74 | * match_font: returns font information for a given Fontconfig pattern 75 | * base64_string_export: encode a string in base64 76 | * version_cairo: runtime version of the Cairo library 77 | * version_freetype: runtime version of the FreeType library 78 | * version_fontconfig: compile-time version of the Fontconfig library 79 | 80 | ## updates 81 | 82 | * CONFIGURE file has been updated with Homebrew new repo (Jeroen Ooms) 83 | * GPL-3 license file has been added 84 | * CairoContext now uses Fontconfig to find system fonts 85 | * CairoContext now supports user-defined font files 86 | 87 | # gdtools 0.0.7 88 | 89 | * Fix to let OS X Snow Leopard produce binaries (Jeroen Ooms) 90 | 91 | # gdtools 0.0.6 92 | 93 | * Fix to prevent OSX CRAN builder from linking 94 | against old libs in /usr/local/lib (Jeroen Ooms) 95 | 96 | # gdtools 0.0.5 97 | 98 | * new function raster_write to write raster object to a png file 99 | * usage of testthat 100 | 101 | # gdtools 0.0.4 102 | 103 | * Fix for Mavericks CRAN builder (Jeroen Ooms) 104 | * Fix for solaris CRAN builder (Jeroen Ooms) 105 | 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # gdtools 5 | 6 | 7 | 8 | [![CRAN 9 | status](https://www.r-pkg.org/badges/version/gdtools)](https://CRAN.R-project.org/package=gdtools) 10 | [![R build 11 | status](https://github.com/davidgohel/gdtools/workflows/R-CMD-check/badge.svg)](https://github.com/davidgohel/gdtools/actions) 12 | [![Coverage 13 | Status](https://img.shields.io/codecov/c/github/davidgohel/gdtools/master.svg)](https://codecov.io/github/davidgohel/gdtools?branch=master) 14 | 15 | 16 | The package `gdtools` provides functionalities to get font metrics and 17 | to generate base64 encoded string from raster matrix. It is used by 18 | package `ggiraph` and `rvg` to allow font metric calculation but can 19 | also be used to compute the exact size a text would have with specific 20 | font options (size, bold, italic). 21 | 22 | ## Installation 23 | 24 | You can install the released version of gdtools from 25 | [CRAN](https://CRAN.R-project.org) with: 26 | 27 | ``` r 28 | install.packages("gdtools") 29 | ``` 30 | 31 | And the development version from 32 | [GitHub](https://github.com/davidgohel/gdtools) with: 33 | 34 | ``` r 35 | # install.packages("devtools") 36 | devtools::install_github("davidgohel/gdtools") 37 | ``` 38 | 39 | ## Example 40 | 41 | ``` r 42 | library(gdtools) 43 | str_extents(c("a string", "a longer string"), 44 | fontsize = 24, bold = TRUE, italic = TRUE) 45 | #> [,1] [,2] 46 | #> [1,] 86.68359 22.60547 47 | #> [2,] 166.68750 22.60547 48 | ``` 49 | 50 | ## For mac os users 51 | 52 | This package needs X11 to be available on mac os machines. This will 53 | make cairo, font-config and other system dependancies available. This is 54 | documented here: [R for Mac OS 55 | X](https://cran.r-project.org/bin/macosx/) ; X11 can be downloaded from 56 | [XQuartz](https://www.xquartz.org/) website. 57 | 58 | - `Unable to load shared object` 59 | 60 | Sometimes, when your OS got updated, some font settings and several 61 | other settings can be changed. An error similar to the one below can 62 | be read : 63 | 64 | Error in dyn.load(file, DLLpath = DLLpath, ...) : 65 | unable to load shared object '/Library/Frameworks/R.framework/Versions/.../gdtools/libs/gdtools.so': 66 | dlopen(/Library/Frameworks/R.framework/Versions/.../gdtools/libs/gdtools.so, 6): Library not loaded: /opt/X11/lib/libcairo.2.dylib 67 | Referenced from: /Library/Frameworks/R.framework/Versions/.../gdtools/libs/gdtools.so 68 | Reason: image not found 69 | 70 | Or 71 | 72 | Error: package or namespace load failed for ‘xxxx’ in dyn.load(file, DLLpath = DLLpath, ...): 73 | unable to load shared object '/Library/Frameworks/R.framework/Versions/.../systemfonts/libs/systemfonts.so': 74 | dlopen(/Library/Frameworks/R.framework/Versions/.../systemfonts/libs/systemfonts.so, 6): Library not loaded: /opt/X11/lib/libfreetype.6.dylib 75 | Referenced from: /Library/Frameworks/R.framework/Versions/.../systemfonts/libs/systemfonts.so 76 | Reason: image not found 77 | 78 | > Solution: 79 | 80 | 1. Close all R sessions 81 | 2. Re-install XQuartz when upgrading your macOS to a new major 82 | version. 83 | 3. Re-install package gdtools. 84 | 85 | If you need to build the package from sources, make sure XCode is 86 | installed and you have accepted the license agreement. 87 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # gdtools 17 | 18 | 19 | [![CRAN status](https://www.r-pkg.org/badges/version/gdtools)](https://CRAN.R-project.org/package=gdtools) 20 | [![R build status](https://github.com/davidgohel/gdtools/workflows/R-CMD-check/badge.svg)](https://github.com/davidgohel/gdtools/actions) 21 | [![Coverage Status](https://img.shields.io/codecov/c/github/davidgohel/gdtools/master.svg)](https://codecov.io/github/davidgohel/gdtools?branch=master) 22 | 23 | 24 | The package `gdtools` provides functionalities to get 25 | font metrics and to generate base64 encoded string from 26 | raster matrix. It is used by package `ggiraph` and `rvg` 27 | to allow font metric calculation but can also be used 28 | to compute the exact size a text would have with 29 | specific font options (size, bold, italic). 30 | 31 | 32 | ## Installation 33 | 34 | You can install the released version of gdtools from [CRAN](https://CRAN.R-project.org) with: 35 | 36 | ``` r 37 | install.packages("gdtools") 38 | ``` 39 | 40 | And the development version from [GitHub](https://github.com/davidgohel/gdtools) with: 41 | 42 | ``` r 43 | # install.packages("devtools") 44 | devtools::install_github("davidgohel/gdtools") 45 | ``` 46 | ## Example 47 | 48 | 49 | ```{r example} 50 | library(gdtools) 51 | str_extents(c("a string", "a longer string"), 52 | fontsize = 24, bold = TRUE, italic = TRUE) 53 | ``` 54 | 55 | ## For mac os users 56 | 57 | This package needs X11 to be available on mac os machines. This will 58 | make cairo, font-config and other system dependancies available. 59 | This is documented here: [R for Mac OS X](https://cran.r-project.org/bin/macosx/) ; 60 | X11 can be downloaded from [XQuartz](https://www.xquartz.org/) website. 61 | 62 | * `Unable to load shared object` 63 | 64 | Sometimes, when your OS got updated, some font settings and several 65 | other settings can be changed. An error similar to the one below can be read : 66 | 67 | ``` 68 | Error in dyn.load(file, DLLpath = DLLpath, ...) : 69 | unable to load shared object '/Library/Frameworks/R.framework/Versions/.../gdtools/libs/gdtools.so': 70 | dlopen(/Library/Frameworks/R.framework/Versions/.../gdtools/libs/gdtools.so, 6): Library not loaded: /opt/X11/lib/libcairo.2.dylib 71 | Referenced from: /Library/Frameworks/R.framework/Versions/.../gdtools/libs/gdtools.so 72 | Reason: image not found 73 | ``` 74 | 75 | Or 76 | 77 | ``` 78 | Error: package or namespace load failed for ‘xxxx’ in dyn.load(file, DLLpath = DLLpath, ...): 79 | unable to load shared object '/Library/Frameworks/R.framework/Versions/.../systemfonts/libs/systemfonts.so': 80 | dlopen(/Library/Frameworks/R.framework/Versions/.../systemfonts/libs/systemfonts.so, 6): Library not loaded: /opt/X11/lib/libfreetype.6.dylib 81 | Referenced from: /Library/Frameworks/R.framework/Versions/.../systemfonts/libs/systemfonts.so 82 | Reason: image not found 83 | ``` 84 | 85 | > Solution: 86 | 87 | 1. Close all R sessions 88 | 2. Re-install XQuartz when upgrading your macOS to a new major version. 89 | 3. Re-install package gdtools. 90 | 91 | If you need to build the package from sources, make sure XCode is installed 92 | and you have accepted the license agreement. 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | # Anticonf script by Jeroen Ooms (2020) 2 | # The script will try 'pkg-config' to find required cflags and ldflags. 3 | # Make sure this executable is in PATH when installing the package. 4 | # Alternatively, you can set INCLUDE_DIR and LIB_DIR manually: 5 | # R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib' 6 | 7 | # Library settings 8 | PKG_CONFIG_NAME="cairo freetype2" 9 | PKG_DEB_NAME="libcairo2-dev" 10 | PKG_RPM_NAME="cairo-devel" 11 | PKG_CSW_NAME="libcairo_dev" 12 | PKG_BREW_NAME="cairo" 13 | PKG_LIBS="-lcairo -lfreetype" 14 | PKG_TEST_FILE="src/tests/sysdeps.c" 15 | 16 | # Prefer static linking on MacOS 17 | if [ `uname` = "Darwin" ]; then 18 | PKG_CONFIG_NAME="--static $PKG_CONFIG_NAME" 19 | if [ `arch` = "i386" ]; then 20 | export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libffi/lib/pkgconfig" 21 | fi 22 | fi 23 | 24 | # Use pkg-config if available 25 | if [ `command -v pkg-config` ]; then 26 | PKGCONFIG_CFLAGS=`pkg-config --cflags ${PKG_CONFIG_NAME}` 27 | PKGCONFIG_LIBS=`pkg-config --libs ${PKG_CONFIG_NAME}` 28 | fi 29 | 30 | # On CRAN do not use pkgconfig cairo (which depends on XQuartz) 31 | if [ -d "/Builds/CRAN-QA-Simon" ] || [ -d "/Volumes/Builds" ]; then 32 | unset PKGCONFIG_CFLAGS 33 | unset PKGCONFIG_LIBS 34 | fi 35 | 36 | # Note that cflags may be empty in case of success 37 | if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then 38 | echo "Found INCLUDE_DIR and/or LIB_DIR!" 39 | PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS" 40 | PKG_LIBS="-L$LIB_DIR $PKG_LIBS" 41 | elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then 42 | echo "Found pkg-config cflags and libs!" 43 | PKG_CFLAGS=${PKGCONFIG_CFLAGS} 44 | PKG_LIBS=${PKGCONFIG_LIBS} 45 | elif [ `uname` = "Darwin" ]; then 46 | brew --version 2>/dev/null 47 | if [ $? -eq 0 ]; then 48 | BREWDIR=`brew --prefix` 49 | PKG_CFLAGS="-I$BREWDIR/include/cairo -I$BREWDIR/include/fontconfig -I$BREWDIR/include/freetype2" 50 | PKG_LIBS="-L$BREWDIR/lib $PKG_LIBS" 51 | else 52 | curl -sfL "https://autobrew.github.io/scripts/cairo" > autobrew 53 | . autobrew 54 | fi 55 | fi 56 | 57 | # Find compiler 58 | CC=`${R_HOME}/bin/R CMD config CC` 59 | CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` 60 | CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS` 61 | 62 | # For debugging 63 | echo "Using PKG_CFLAGS=$PKG_CFLAGS" 64 | echo "Using PKG_LIBS=$PKG_LIBS" 65 | 66 | # Test configuration 67 | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E ${PKG_TEST_FILE} >/dev/null 2>configure.log 68 | if [ $? -ne 0 ]; then 69 | echo "-----------------------------[ ANTICONF ]-------------------------------" 70 | echo "Configuration failed to find libraries. Try installing:" 71 | echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu)" 72 | echo " * rpm: $PKG_RPM_NAME (Fedora, CentOS, RHEL)" 73 | echo " * csw: $PKG_CSW_NAME (Solaris)" 74 | echo " * brew: $PKG_BREW_NAME (OSX)" 75 | echo "If $PKG_CONFIG_NAME are already installed, check that 'pkg-config' is in your" 76 | echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config" 77 | echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:" 78 | echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'" 79 | echo "---------------------------[ ERROR MESSAGE ]----------------------------" 80 | cat configure.log 81 | echo "------------------------------------------------------------------------" 82 | exit 1 83 | fi 84 | 85 | # Write to Makevars 86 | sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars 87 | 88 | # Success 89 | exit 0 90 | -------------------------------------------------------------------------------- /src/CairoContext.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include FT_FREETYPE_H 10 | #include "gdtools_types.h" 11 | 12 | using namespace Rcpp; 13 | 14 | struct CairoContext::CairoContext_ { 15 | cairo_surface_t* surface; 16 | cairo_t* context; 17 | 18 | FT_Library library; 19 | fontCache fonts; 20 | }; 21 | 22 | CairoContext::CairoContext() { 23 | cairo_ = new CairoContext_(); 24 | cairo_->surface = cairo_pdf_surface_create(NULL, 720, 720); 25 | cairo_->context = cairo_create(cairo_->surface); 26 | 27 | if (FT_Init_FreeType(&(cairo_->library))) 28 | Rcpp::stop("FreeType error: unable to initialize FreeType library object"); 29 | } 30 | 31 | CairoContext::~CairoContext() { 32 | fontCache::iterator it = cairo_->fonts.begin(); 33 | while (it != cairo_->fonts.end()) { 34 | cairo_font_face_destroy(it->second); 35 | ++it; 36 | } 37 | 38 | cairo_surface_destroy(cairo_->surface); 39 | cairo_destroy(cairo_->context); 40 | 41 | delete cairo_; 42 | } 43 | 44 | void CairoContext::cacheFont(fontCache& cache, std::string& key, 45 | std::string fontfile, int fontindex) { 46 | FT_Face face; 47 | if (0 != FT_New_Face(cairo_->library, fontfile.c_str(), fontindex, &face)) 48 | Rcpp::stop("FreeType error: unable to open %s", fontfile.c_str()); 49 | 50 | cairo_font_face_t* cairo_face = cairo_ft_font_face_create_for_ft_face(face, 0); 51 | 52 | cairo_user_data_key_t font_key; 53 | cairo_status_t status = cairo_font_face_set_user_data( 54 | cairo_face, &font_key, face, (cairo_destroy_func_t) FT_Done_Face 55 | ); 56 | if (status) { 57 | cairo_font_face_destroy(cairo_face); 58 | FT_Done_Face(face); 59 | Rcpp::stop("Cairo error: unable to handle %s", fontfile.c_str()); 60 | } 61 | 62 | cache[key] = cairo_face; 63 | } 64 | 65 | struct font_file_t { 66 | std::string file; 67 | int index; 68 | }; 69 | 70 | static int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) { 71 | static int (*p_locate_font)(const char *family, int italic, int bold, char *path, int max_path_length) = NULL; 72 | if (p_locate_font == NULL) { 73 | p_locate_font = (int(*)(const char *, int, int, char *, int)) R_GetCCallable("systemfonts", "locate_font"); 74 | } 75 | return p_locate_font(family, italic, bold, path, max_path_length); 76 | } 77 | 78 | 79 | font_file_t findFontFile(const char* fontname, int bold, int italic) { 80 | 81 | char *path = new char[PATH_MAX+1]; 82 | path[PATH_MAX] = '\0'; 83 | 84 | font_file_t output; 85 | output.index = locate_font(fontname, italic, bold, path, PATH_MAX); 86 | output.file = path; 87 | delete[] path; 88 | if (output.file.size()) 89 | return output; 90 | else 91 | Rcpp::stop("error: unable to match font pattern"); 92 | } 93 | 94 | void CairoContext::setFont(std::string fontname, double fontsize, 95 | bool bold, bool italic, std::string fontfile) { 96 | std::string key; 97 | if (fontfile.size()) { 98 | // Use file path as key to cached elements 99 | key = fontfile; 100 | if (cairo_->fonts.find(key) == cairo_->fonts.end()) { 101 | cacheFont(cairo_->fonts, key, fontfile, 0); 102 | } 103 | } else { 104 | // Use font name and bold/italic properties as key 105 | char props[20]; 106 | snprintf(props, sizeof(props), " %d %d", (int) bold, (int) italic); 107 | key = fontname + props; 108 | if (cairo_->fonts.find(key) == cairo_->fonts.end()) { 109 | // Add font to cache 110 | font_file_t fontfile = findFontFile(fontname.c_str(), bold, italic); 111 | cacheFont(cairo_->fonts, key, fontfile.file, fontfile.index); 112 | } 113 | } 114 | 115 | cairo_set_font_size(cairo_->context, fontsize); 116 | cairo_set_font_face(cairo_->context, cairo_->fonts[key]); 117 | } 118 | 119 | FontMetric CairoContext::getExtents(std::string x) { 120 | // cairo_text_extents_t te; 121 | // cairo_text_extents(cairo_->context, x.c_str(), &te); 122 | 123 | // FontMetric fm; 124 | // fm.height = te.height; 125 | // fm.width = te.x_advance; 126 | // fm.ascent = -te.y_bearing; 127 | // fm.descent = te.height + te.y_bearing; 128 | 129 | 130 | FontMetric fm; 131 | fm.height = 0; 132 | fm.width = 0; 133 | 134 | while (x.length() > 0) { 135 | std::string sstr; 136 | 137 | size_t pos = x.find('\n'); 138 | if (pos == std::string::npos) { 139 | sstr = x; 140 | x = ""; 141 | } else { 142 | sstr = x.substr(0, pos); 143 | x = x.substr(pos + 1); 144 | } 145 | 146 | cairo_text_extents_t te; 147 | cairo_text_extents(cairo_->context, sstr.c_str(), &te); 148 | fm.height += te.height; 149 | fm.width = std::max(fm.width, te.x_advance); 150 | // TODO: Do we need to accumulate `ascent` and `descent`? 151 | fm.ascent += -te.y_bearing; 152 | fm.descent += te.height + te.y_bearing; 153 | } 154 | 155 | return fm; 156 | } 157 | 158 | 159 | bool CairoContext::validateGlyphs(std::string x) { 160 | 161 | cairo_glyph_t* glyphs = NULL; 162 | int glyph_count; 163 | cairo_text_cluster_t* clusters = NULL; 164 | int cluster_count; 165 | cairo_text_cluster_flags_t clusterflags; 166 | bool out = true; 167 | 168 | cairo_status_t status = cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cairo_->context), 0, 0, x.c_str(), x.size(), &glyphs, &glyph_count, &clusters, &cluster_count, 169 | &clusterflags); 170 | 171 | if (status == CAIRO_STATUS_SUCCESS) { 172 | 173 | // for each cluster 174 | int glyph_index = 0; 175 | for (int i = 0; i < cluster_count; i++) { 176 | cairo_text_cluster_t* cluster = &clusters[i]; 177 | 178 | cairo_glyph_t* clusterglyphs = &glyphs[glyph_index]; 179 | if( clusterglyphs[0].index < 1 ){ 180 | out = false; 181 | break; 182 | } 183 | 184 | glyph_index += cluster->num_glyphs; 185 | } 186 | } else stop("Could not get table of glyphs"); 187 | 188 | cairo_glyph_free(glyphs); 189 | cairo_text_cluster_free(clusters); 190 | 191 | return out; 192 | } 193 | -------------------------------------------------------------------------------- /src/raster_to_base64.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "cairo.h" 8 | 9 | using namespace Rcpp; 10 | using namespace std; 11 | 12 | // [[Rcpp::interfaces(r, cpp)]] 13 | 14 | #define R_RED(col) (((col) )&255) 15 | #define R_GREEN(col) (((col)>> 8)&255) 16 | #define R_BLUE(col) (((col)>>16)&255) 17 | #define R_ALPHA(col) (((col)>>24)&255) 18 | 19 | static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 20 | "abcdefghijklmnopqrstuvwxyz" 21 | "0123456789+/"; 22 | 23 | std::string base64_encode(std::vector data) { 24 | 25 | unsigned int in_len = data.size(); 26 | unsigned char* bytes_to_encode = 27 | reinterpret_cast(data.data()); 28 | 29 | std::string ret; 30 | int i = 0; 31 | int j = 0; 32 | unsigned char char_array_3[3]; 33 | unsigned char char_array_4[4]; 34 | 35 | while (in_len--) { 36 | char_array_3[i++] = *(bytes_to_encode++); 37 | if (i == 3) { 38 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 39 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) 40 | + ((char_array_3[1] & 0xf0) >> 4); 41 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) 42 | + ((char_array_3[2] & 0xc0) >> 6); 43 | char_array_4[3] = char_array_3[2] & 0x3f; 44 | 45 | for (i = 0; (i < 4); i++) 46 | ret += base64_chars[char_array_4[i]]; 47 | i = 0; 48 | } 49 | } 50 | 51 | if (i) { 52 | for (j = i; j < 3; j++) 53 | char_array_3[j] = '\0'; 54 | 55 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 56 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) 57 | + ((char_array_3[1] & 0xf0) >> 4); 58 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) 59 | + ((char_array_3[2] & 0xc0) >> 6); 60 | char_array_4[3] = char_array_3[2] & 0x3f; 61 | 62 | for (j = 0; (j < i + 1); j++) 63 | ret += base64_chars[char_array_4[j]]; 64 | 65 | while ((i++ < 3)) 66 | ret += '='; 67 | 68 | } 69 | 70 | return ret; 71 | 72 | } 73 | 74 | static cairo_status_t stream_data(void* closure, const unsigned char* data, unsigned int length) { 75 | vector* in = reinterpret_cast*>(closure); 76 | for (unsigned int i = 0; i < length; ++i) 77 | in->push_back(data[i]); 78 | return CAIRO_STATUS_SUCCESS; 79 | } 80 | 81 | /* The Cairo raster code is adapted from R's X11 device 82 | (c) 2010 R Development Core Team, GPL 2+ */ 83 | cairo_surface_t* raster_paint_surface(std::vector& raster, 84 | int w, int h, double width, double height, 85 | int interpolate) { 86 | int img_width = static_cast (std::ceil(width)); 87 | int img_height = static_cast (std::ceil(height)); 88 | 89 | cairo_surface_t* base_surface = cairo_image_surface_create( 90 | CAIRO_FORMAT_ARGB32, img_width, img_height 91 | ); 92 | cairo_t* cc = cairo_create(base_surface); 93 | 94 | double w_factor = width / w; 95 | double h_factor = height / h; 96 | if (std::isnan(w_factor)) w_factor = 1; 97 | if (std::isnan(h_factor)) h_factor = 1; 98 | cairo_scale(cc, w_factor, h_factor); 99 | 100 | std::vector imageData(4 * w * h); 101 | for (int i = 0; i < w * h; i++) { 102 | int alpha = R_ALPHA(raster[i]); 103 | imageData[i*4 + 3] = alpha; 104 | if (alpha < 255) { 105 | imageData[i*4 + 2] = R_RED(raster[i]) * alpha / 255; 106 | imageData[i*4 + 1] = R_GREEN(raster[i]) * alpha / 255; 107 | imageData[i*4 + 0] = R_BLUE(raster[i]) * alpha / 255; 108 | } else { 109 | imageData[i*4 + 2] = R_RED(raster[i]); 110 | imageData[i*4 + 1] = R_GREEN(raster[i]); 111 | imageData[i*4 + 0] = R_BLUE(raster[i]); 112 | } 113 | } 114 | 115 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); 116 | cairo_surface_t* image = cairo_image_surface_create_for_data( 117 | &imageData[0], CAIRO_FORMAT_ARGB32, w, h, stride 118 | ); 119 | 120 | cairo_set_source_surface(cc, image, 0, 0); 121 | if (interpolate > 0) { 122 | cairo_pattern_set_filter(cairo_get_source(cc), CAIRO_FILTER_BILINEAR); 123 | cairo_pattern_set_extend(cairo_get_source(cc), CAIRO_EXTEND_PAD); 124 | } else 125 | cairo_pattern_set_filter(cairo_get_source(cc), CAIRO_FILTER_NEAREST); 126 | 127 | cairo_new_path(cc); 128 | cairo_rectangle(cc, 0, 0, w, h); 129 | cairo_clip(cc); 130 | cairo_paint(cc); 131 | 132 | cairo_destroy(cc); 133 | cairo_surface_destroy(image); 134 | 135 | return base_surface; 136 | } 137 | 138 | // [[Rcpp::export]] 139 | std::string raster_to_str(std::vector raster, 140 | int w, int h, double width, double height, 141 | int interpolate) { 142 | cairo_surface_t* surface = raster_paint_surface( 143 | raster, w, h, width, height, interpolate 144 | ); 145 | 146 | std::vector in; 147 | cairo_surface_write_to_png_stream(surface, stream_data, &in); 148 | cairo_surface_destroy(surface); 149 | 150 | return base64_encode(in); 151 | } 152 | 153 | // [[Rcpp::export]] 154 | int raster_to_file(std::vector raster, 155 | int w, int h, double width, double height, 156 | int interpolate, std::string filename) { 157 | cairo_surface_t* surface = raster_paint_surface( 158 | raster, w, h, width, height, interpolate 159 | ); 160 | 161 | cairo_surface_write_to_png(surface, filename.c_str()); 162 | cairo_surface_destroy(surface); 163 | 164 | return 1; 165 | } 166 | 167 | vector convert_hex(vector hcode) { 168 | vector bit_coded_colors(hcode.size()); 169 | 170 | for( size_t i = 0 ; i < hcode.size() ; i++ ){ 171 | std::stringstream str_abgr; 172 | unsigned int bit_coded_color; 173 | string in = "0x"; 174 | 175 | if( hcode[i].size() == 9 ) { 176 | in += hcode[i].substr(7, 2 ); 177 | } else in += "FF"; 178 | 179 | in += hcode[i].substr(5, 2 ); 180 | in += hcode[i].substr(3, 2 ); 181 | in += hcode[i].substr(1, 2 ); 182 | 183 | str_abgr << std::hex << in; 184 | str_abgr >> bit_coded_color; 185 | 186 | bit_coded_colors[i] = bit_coded_color; 187 | } 188 | return bit_coded_colors; 189 | } 190 | 191 | // [[Rcpp::export]] 192 | bool raster_png_(CharacterVector raster_, int w, int h, double width, double height, 193 | int interpolate, std::string filename) { 194 | vector raster = Rcpp::as >(raster_); 195 | vector out = convert_hex(raster); 196 | raster_to_file(out, w, h, width, height, interpolate, filename); 197 | return true; 198 | } 199 | 200 | // [[Rcpp::export]] 201 | std::string base64_raster_encode(CharacterVector raster_, int w, int h, double width, double height, 202 | int interpolate) { 203 | vector raster = Rcpp::as >(raster_); 204 | vector out = convert_hex(raster); 205 | return raster_to_str(out, w, h, width, height, interpolate); 206 | } 207 | 208 | // Encode a file into base64. 209 | // [[Rcpp::export]] 210 | std::string base64_file_encode(std::string filename) { 211 | ifstream ifs(filename.c_str(), ios::binary | ios::ate); 212 | if (!ifs.good()) 213 | stop("Failed to open %s", filename); 214 | 215 | ifstream::pos_type pos = ifs.tellg(); 216 | 217 | std::vector result(pos); 218 | 219 | ifs.seekg(0, ios::beg); 220 | ifs.read(&result[0], pos); 221 | ifs.close(); 222 | 223 | return base64_encode(result); 224 | } 225 | 226 | // [[Rcpp::export]] 227 | std::string base64_string_encode(std::string string) { 228 | std::vector chars(string.begin(), string.end()); 229 | return base64_encode(chars); 230 | } 231 | -------------------------------------------------------------------------------- /inst/include/gdtools_RcppExports.h: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #ifndef RCPP_gdtools_RCPPEXPORTS_H_GEN_ 5 | #define RCPP_gdtools_RCPPEXPORTS_H_GEN_ 6 | 7 | #include "gdtools_types.h" 8 | #include 9 | 10 | namespace gdtools { 11 | 12 | using namespace Rcpp; 13 | 14 | namespace { 15 | void validateSignature(const char* sig) { 16 | Rcpp::Function require = Rcpp::Environment::base_env()["require"]; 17 | require("gdtools", Rcpp::Named("quietly") = true); 18 | typedef int(*Ptr_validate)(const char*); 19 | static Ptr_validate p_validate = (Ptr_validate) 20 | R_GetCCallable("gdtools", "_gdtools_RcppExport_validate"); 21 | if (!p_validate(sig)) { 22 | throw Rcpp::function_not_exported( 23 | "C++ function with signature '" + std::string(sig) + "' not found in gdtools"); 24 | } 25 | } 26 | } 27 | 28 | inline XPtrCairoContext context_create() { 29 | typedef SEXP(*Ptr_context_create)(); 30 | static Ptr_context_create p_context_create = NULL; 31 | if (p_context_create == NULL) { 32 | validateSignature("XPtrCairoContext(*context_create)()"); 33 | p_context_create = (Ptr_context_create)R_GetCCallable("gdtools", "_gdtools_context_create"); 34 | } 35 | RObject rcpp_result_gen; 36 | { 37 | RNGScope RCPP_rngScope_gen; 38 | rcpp_result_gen = p_context_create(); 39 | } 40 | if (rcpp_result_gen.inherits("interrupted-error")) 41 | throw Rcpp::internal::InterruptedException(); 42 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 43 | throw Rcpp::LongjumpException(rcpp_result_gen); 44 | if (rcpp_result_gen.inherits("try-error")) 45 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 46 | return Rcpp::as(rcpp_result_gen); 47 | } 48 | 49 | inline bool context_set_font(XPtrCairoContext cc, std::string fontname, double fontsize, bool bold, bool italic, std::string fontfile = "") { 50 | typedef SEXP(*Ptr_context_set_font)(SEXP,SEXP,SEXP,SEXP,SEXP,SEXP); 51 | static Ptr_context_set_font p_context_set_font = NULL; 52 | if (p_context_set_font == NULL) { 53 | validateSignature("bool(*context_set_font)(XPtrCairoContext,std::string,double,bool,bool,std::string)"); 54 | p_context_set_font = (Ptr_context_set_font)R_GetCCallable("gdtools", "_gdtools_context_set_font"); 55 | } 56 | RObject rcpp_result_gen; 57 | { 58 | RNGScope RCPP_rngScope_gen; 59 | rcpp_result_gen = p_context_set_font(Shield(Rcpp::wrap(cc)), Shield(Rcpp::wrap(fontname)), Shield(Rcpp::wrap(fontsize)), Shield(Rcpp::wrap(bold)), Shield(Rcpp::wrap(italic)), Shield(Rcpp::wrap(fontfile))); 60 | } 61 | if (rcpp_result_gen.inherits("interrupted-error")) 62 | throw Rcpp::internal::InterruptedException(); 63 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 64 | throw Rcpp::LongjumpException(rcpp_result_gen); 65 | if (rcpp_result_gen.inherits("try-error")) 66 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 67 | return Rcpp::as(rcpp_result_gen); 68 | } 69 | 70 | inline FontMetric context_extents(XPtrCairoContext cc, std::string x) { 71 | typedef SEXP(*Ptr_context_extents)(SEXP,SEXP); 72 | static Ptr_context_extents p_context_extents = NULL; 73 | if (p_context_extents == NULL) { 74 | validateSignature("FontMetric(*context_extents)(XPtrCairoContext,std::string)"); 75 | p_context_extents = (Ptr_context_extents)R_GetCCallable("gdtools", "_gdtools_context_extents"); 76 | } 77 | RObject rcpp_result_gen; 78 | { 79 | RNGScope RCPP_rngScope_gen; 80 | rcpp_result_gen = p_context_extents(Shield(Rcpp::wrap(cc)), Shield(Rcpp::wrap(x))); 81 | } 82 | if (rcpp_result_gen.inherits("interrupted-error")) 83 | throw Rcpp::internal::InterruptedException(); 84 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 85 | throw Rcpp::LongjumpException(rcpp_result_gen); 86 | if (rcpp_result_gen.inherits("try-error")) 87 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 88 | return Rcpp::as(rcpp_result_gen); 89 | } 90 | 91 | inline std::string raster_to_str(std::vector raster, int w, int h, double width, double height, int interpolate) { 92 | typedef SEXP(*Ptr_raster_to_str)(SEXP,SEXP,SEXP,SEXP,SEXP,SEXP); 93 | static Ptr_raster_to_str p_raster_to_str = NULL; 94 | if (p_raster_to_str == NULL) { 95 | validateSignature("std::string(*raster_to_str)(std::vector,int,int,double,double,int)"); 96 | p_raster_to_str = (Ptr_raster_to_str)R_GetCCallable("gdtools", "_gdtools_raster_to_str"); 97 | } 98 | RObject rcpp_result_gen; 99 | { 100 | RNGScope RCPP_rngScope_gen; 101 | rcpp_result_gen = p_raster_to_str(Shield(Rcpp::wrap(raster)), Shield(Rcpp::wrap(w)), Shield(Rcpp::wrap(h)), Shield(Rcpp::wrap(width)), Shield(Rcpp::wrap(height)), Shield(Rcpp::wrap(interpolate))); 102 | } 103 | if (rcpp_result_gen.inherits("interrupted-error")) 104 | throw Rcpp::internal::InterruptedException(); 105 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 106 | throw Rcpp::LongjumpException(rcpp_result_gen); 107 | if (rcpp_result_gen.inherits("try-error")) 108 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 109 | return Rcpp::as(rcpp_result_gen); 110 | } 111 | 112 | inline int raster_to_file(std::vector raster, int w, int h, double width, double height, int interpolate, std::string filename) { 113 | typedef SEXP(*Ptr_raster_to_file)(SEXP,SEXP,SEXP,SEXP,SEXP,SEXP,SEXP); 114 | static Ptr_raster_to_file p_raster_to_file = NULL; 115 | if (p_raster_to_file == NULL) { 116 | validateSignature("int(*raster_to_file)(std::vector,int,int,double,double,int,std::string)"); 117 | p_raster_to_file = (Ptr_raster_to_file)R_GetCCallable("gdtools", "_gdtools_raster_to_file"); 118 | } 119 | RObject rcpp_result_gen; 120 | { 121 | RNGScope RCPP_rngScope_gen; 122 | rcpp_result_gen = p_raster_to_file(Shield(Rcpp::wrap(raster)), Shield(Rcpp::wrap(w)), Shield(Rcpp::wrap(h)), Shield(Rcpp::wrap(width)), Shield(Rcpp::wrap(height)), Shield(Rcpp::wrap(interpolate)), Shield(Rcpp::wrap(filename))); 123 | } 124 | if (rcpp_result_gen.inherits("interrupted-error")) 125 | throw Rcpp::internal::InterruptedException(); 126 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 127 | throw Rcpp::LongjumpException(rcpp_result_gen); 128 | if (rcpp_result_gen.inherits("try-error")) 129 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 130 | return Rcpp::as(rcpp_result_gen); 131 | } 132 | 133 | inline bool raster_png_(CharacterVector raster_, int w, int h, double width, double height, int interpolate, std::string filename) { 134 | typedef SEXP(*Ptr_raster_png_)(SEXP,SEXP,SEXP,SEXP,SEXP,SEXP,SEXP); 135 | static Ptr_raster_png_ p_raster_png_ = NULL; 136 | if (p_raster_png_ == NULL) { 137 | validateSignature("bool(*raster_png_)(CharacterVector,int,int,double,double,int,std::string)"); 138 | p_raster_png_ = (Ptr_raster_png_)R_GetCCallable("gdtools", "_gdtools_raster_png_"); 139 | } 140 | RObject rcpp_result_gen; 141 | { 142 | RNGScope RCPP_rngScope_gen; 143 | rcpp_result_gen = p_raster_png_(Shield(Rcpp::wrap(raster_)), Shield(Rcpp::wrap(w)), Shield(Rcpp::wrap(h)), Shield(Rcpp::wrap(width)), Shield(Rcpp::wrap(height)), Shield(Rcpp::wrap(interpolate)), Shield(Rcpp::wrap(filename))); 144 | } 145 | if (rcpp_result_gen.inherits("interrupted-error")) 146 | throw Rcpp::internal::InterruptedException(); 147 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 148 | throw Rcpp::LongjumpException(rcpp_result_gen); 149 | if (rcpp_result_gen.inherits("try-error")) 150 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 151 | return Rcpp::as(rcpp_result_gen); 152 | } 153 | 154 | inline std::string base64_raster_encode(CharacterVector raster_, int w, int h, double width, double height, int interpolate) { 155 | typedef SEXP(*Ptr_base64_raster_encode)(SEXP,SEXP,SEXP,SEXP,SEXP,SEXP); 156 | static Ptr_base64_raster_encode p_base64_raster_encode = NULL; 157 | if (p_base64_raster_encode == NULL) { 158 | validateSignature("std::string(*base64_raster_encode)(CharacterVector,int,int,double,double,int)"); 159 | p_base64_raster_encode = (Ptr_base64_raster_encode)R_GetCCallable("gdtools", "_gdtools_base64_raster_encode"); 160 | } 161 | RObject rcpp_result_gen; 162 | { 163 | RNGScope RCPP_rngScope_gen; 164 | rcpp_result_gen = p_base64_raster_encode(Shield(Rcpp::wrap(raster_)), Shield(Rcpp::wrap(w)), Shield(Rcpp::wrap(h)), Shield(Rcpp::wrap(width)), Shield(Rcpp::wrap(height)), Shield(Rcpp::wrap(interpolate))); 165 | } 166 | if (rcpp_result_gen.inherits("interrupted-error")) 167 | throw Rcpp::internal::InterruptedException(); 168 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 169 | throw Rcpp::LongjumpException(rcpp_result_gen); 170 | if (rcpp_result_gen.inherits("try-error")) 171 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 172 | return Rcpp::as(rcpp_result_gen); 173 | } 174 | 175 | inline std::string base64_file_encode(std::string filename) { 176 | typedef SEXP(*Ptr_base64_file_encode)(SEXP); 177 | static Ptr_base64_file_encode p_base64_file_encode = NULL; 178 | if (p_base64_file_encode == NULL) { 179 | validateSignature("std::string(*base64_file_encode)(std::string)"); 180 | p_base64_file_encode = (Ptr_base64_file_encode)R_GetCCallable("gdtools", "_gdtools_base64_file_encode"); 181 | } 182 | RObject rcpp_result_gen; 183 | { 184 | RNGScope RCPP_rngScope_gen; 185 | rcpp_result_gen = p_base64_file_encode(Shield(Rcpp::wrap(filename))); 186 | } 187 | if (rcpp_result_gen.inherits("interrupted-error")) 188 | throw Rcpp::internal::InterruptedException(); 189 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 190 | throw Rcpp::LongjumpException(rcpp_result_gen); 191 | if (rcpp_result_gen.inherits("try-error")) 192 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 193 | return Rcpp::as(rcpp_result_gen); 194 | } 195 | 196 | inline std::string base64_string_encode(std::string string) { 197 | typedef SEXP(*Ptr_base64_string_encode)(SEXP); 198 | static Ptr_base64_string_encode p_base64_string_encode = NULL; 199 | if (p_base64_string_encode == NULL) { 200 | validateSignature("std::string(*base64_string_encode)(std::string)"); 201 | p_base64_string_encode = (Ptr_base64_string_encode)R_GetCCallable("gdtools", "_gdtools_base64_string_encode"); 202 | } 203 | RObject rcpp_result_gen; 204 | { 205 | RNGScope RCPP_rngScope_gen; 206 | rcpp_result_gen = p_base64_string_encode(Shield(Rcpp::wrap(string))); 207 | } 208 | if (rcpp_result_gen.inherits("interrupted-error")) 209 | throw Rcpp::internal::InterruptedException(); 210 | if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) 211 | throw Rcpp::LongjumpException(rcpp_result_gen); 212 | if (rcpp_result_gen.inherits("try-error")) 213 | throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); 214 | return Rcpp::as(rcpp_result_gen); 215 | } 216 | 217 | } 218 | 219 | #endif // RCPP_gdtools_RCPPEXPORTS_H_GEN_ 220 | -------------------------------------------------------------------------------- /src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include "../inst/include/gdtools.h" 5 | #include "../inst/include/gdtools_types.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace Rcpp; 11 | 12 | // str_extents_ 13 | NumericMatrix str_extents_(CharacterVector x, std::string fontname, double fontsize, int bold, int italic, std::string fontfile); 14 | RcppExport SEXP _gdtools_str_extents_(SEXP xSEXP, SEXP fontnameSEXP, SEXP fontsizeSEXP, SEXP boldSEXP, SEXP italicSEXP, SEXP fontfileSEXP) { 15 | BEGIN_RCPP 16 | Rcpp::RObject rcpp_result_gen; 17 | Rcpp::RNGScope rcpp_rngScope_gen; 18 | Rcpp::traits::input_parameter< CharacterVector >::type x(xSEXP); 19 | Rcpp::traits::input_parameter< std::string >::type fontname(fontnameSEXP); 20 | Rcpp::traits::input_parameter< double >::type fontsize(fontsizeSEXP); 21 | Rcpp::traits::input_parameter< int >::type bold(boldSEXP); 22 | Rcpp::traits::input_parameter< int >::type italic(italicSEXP); 23 | Rcpp::traits::input_parameter< std::string >::type fontfile(fontfileSEXP); 24 | rcpp_result_gen = Rcpp::wrap(str_extents_(x, fontname, fontsize, bold, italic, fontfile)); 25 | return rcpp_result_gen; 26 | END_RCPP 27 | } 28 | // str_metrics_ 29 | NumericVector str_metrics_(CharacterVector x, std::string fontname, double fontsize, int bold, int italic, std::string fontfile); 30 | RcppExport SEXP _gdtools_str_metrics_(SEXP xSEXP, SEXP fontnameSEXP, SEXP fontsizeSEXP, SEXP boldSEXP, SEXP italicSEXP, SEXP fontfileSEXP) { 31 | BEGIN_RCPP 32 | Rcpp::RObject rcpp_result_gen; 33 | Rcpp::RNGScope rcpp_rngScope_gen; 34 | Rcpp::traits::input_parameter< CharacterVector >::type x(xSEXP); 35 | Rcpp::traits::input_parameter< std::string >::type fontname(fontnameSEXP); 36 | Rcpp::traits::input_parameter< double >::type fontsize(fontsizeSEXP); 37 | Rcpp::traits::input_parameter< int >::type bold(boldSEXP); 38 | Rcpp::traits::input_parameter< int >::type italic(italicSEXP); 39 | Rcpp::traits::input_parameter< std::string >::type fontfile(fontfileSEXP); 40 | rcpp_result_gen = Rcpp::wrap(str_metrics_(x, fontname, fontsize, bold, italic, fontfile)); 41 | return rcpp_result_gen; 42 | END_RCPP 43 | } 44 | // m_str_extents_ 45 | NumericMatrix m_str_extents_(CharacterVector x, std::vector fontname, std::vector fontsize, std::vector bold, std::vector italic, std::vector fontfile); 46 | RcppExport SEXP _gdtools_m_str_extents_(SEXP xSEXP, SEXP fontnameSEXP, SEXP fontsizeSEXP, SEXP boldSEXP, SEXP italicSEXP, SEXP fontfileSEXP) { 47 | BEGIN_RCPP 48 | Rcpp::RObject rcpp_result_gen; 49 | Rcpp::RNGScope rcpp_rngScope_gen; 50 | Rcpp::traits::input_parameter< CharacterVector >::type x(xSEXP); 51 | Rcpp::traits::input_parameter< std::vector >::type fontname(fontnameSEXP); 52 | Rcpp::traits::input_parameter< std::vector >::type fontsize(fontsizeSEXP); 53 | Rcpp::traits::input_parameter< std::vector >::type bold(boldSEXP); 54 | Rcpp::traits::input_parameter< std::vector >::type italic(italicSEXP); 55 | Rcpp::traits::input_parameter< std::vector >::type fontfile(fontfileSEXP); 56 | rcpp_result_gen = Rcpp::wrap(m_str_extents_(x, fontname, fontsize, bold, italic, fontfile)); 57 | return rcpp_result_gen; 58 | END_RCPP 59 | } 60 | // glyphs_match_ 61 | LogicalVector glyphs_match_(CharacterVector x, std::string fontname, int bold, int italic, std::string fontfile); 62 | RcppExport SEXP _gdtools_glyphs_match_(SEXP xSEXP, SEXP fontnameSEXP, SEXP boldSEXP, SEXP italicSEXP, SEXP fontfileSEXP) { 63 | BEGIN_RCPP 64 | Rcpp::RObject rcpp_result_gen; 65 | Rcpp::RNGScope rcpp_rngScope_gen; 66 | Rcpp::traits::input_parameter< CharacterVector >::type x(xSEXP); 67 | Rcpp::traits::input_parameter< std::string >::type fontname(fontnameSEXP); 68 | Rcpp::traits::input_parameter< int >::type bold(boldSEXP); 69 | Rcpp::traits::input_parameter< int >::type italic(italicSEXP); 70 | Rcpp::traits::input_parameter< std::string >::type fontfile(fontfileSEXP); 71 | rcpp_result_gen = Rcpp::wrap(glyphs_match_(x, fontname, bold, italic, fontfile)); 72 | return rcpp_result_gen; 73 | END_RCPP 74 | } 75 | // context_create 76 | XPtrCairoContext context_create(); 77 | static SEXP _gdtools_context_create_try() { 78 | BEGIN_RCPP 79 | Rcpp::RObject rcpp_result_gen; 80 | rcpp_result_gen = Rcpp::wrap(context_create()); 81 | return rcpp_result_gen; 82 | END_RCPP_RETURN_ERROR 83 | } 84 | RcppExport SEXP _gdtools_context_create() { 85 | SEXP rcpp_result_gen; 86 | { 87 | Rcpp::RNGScope rcpp_rngScope_gen; 88 | rcpp_result_gen = PROTECT(_gdtools_context_create_try()); 89 | } 90 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 91 | if (rcpp_isInterrupt_gen) { 92 | UNPROTECT(1); 93 | Rf_onintr(); 94 | } 95 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 96 | if (rcpp_isLongjump_gen) { 97 | Rcpp::internal::resumeJump(rcpp_result_gen); 98 | } 99 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 100 | if (rcpp_isError_gen) { 101 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 102 | UNPROTECT(1); 103 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 104 | } 105 | UNPROTECT(1); 106 | return rcpp_result_gen; 107 | } 108 | // context_set_font 109 | bool context_set_font(XPtrCairoContext cc, std::string fontname, double fontsize, bool bold, bool italic, std::string fontfile); 110 | static SEXP _gdtools_context_set_font_try(SEXP ccSEXP, SEXP fontnameSEXP, SEXP fontsizeSEXP, SEXP boldSEXP, SEXP italicSEXP, SEXP fontfileSEXP) { 111 | BEGIN_RCPP 112 | Rcpp::RObject rcpp_result_gen; 113 | Rcpp::traits::input_parameter< XPtrCairoContext >::type cc(ccSEXP); 114 | Rcpp::traits::input_parameter< std::string >::type fontname(fontnameSEXP); 115 | Rcpp::traits::input_parameter< double >::type fontsize(fontsizeSEXP); 116 | Rcpp::traits::input_parameter< bool >::type bold(boldSEXP); 117 | Rcpp::traits::input_parameter< bool >::type italic(italicSEXP); 118 | Rcpp::traits::input_parameter< std::string >::type fontfile(fontfileSEXP); 119 | rcpp_result_gen = Rcpp::wrap(context_set_font(cc, fontname, fontsize, bold, italic, fontfile)); 120 | return rcpp_result_gen; 121 | END_RCPP_RETURN_ERROR 122 | } 123 | RcppExport SEXP _gdtools_context_set_font(SEXP ccSEXP, SEXP fontnameSEXP, SEXP fontsizeSEXP, SEXP boldSEXP, SEXP italicSEXP, SEXP fontfileSEXP) { 124 | SEXP rcpp_result_gen; 125 | { 126 | Rcpp::RNGScope rcpp_rngScope_gen; 127 | rcpp_result_gen = PROTECT(_gdtools_context_set_font_try(ccSEXP, fontnameSEXP, fontsizeSEXP, boldSEXP, italicSEXP, fontfileSEXP)); 128 | } 129 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 130 | if (rcpp_isInterrupt_gen) { 131 | UNPROTECT(1); 132 | Rf_onintr(); 133 | } 134 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 135 | if (rcpp_isLongjump_gen) { 136 | Rcpp::internal::resumeJump(rcpp_result_gen); 137 | } 138 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 139 | if (rcpp_isError_gen) { 140 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 141 | UNPROTECT(1); 142 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 143 | } 144 | UNPROTECT(1); 145 | return rcpp_result_gen; 146 | } 147 | // context_extents 148 | FontMetric context_extents(XPtrCairoContext cc, std::string x); 149 | static SEXP _gdtools_context_extents_try(SEXP ccSEXP, SEXP xSEXP) { 150 | BEGIN_RCPP 151 | Rcpp::RObject rcpp_result_gen; 152 | Rcpp::traits::input_parameter< XPtrCairoContext >::type cc(ccSEXP); 153 | Rcpp::traits::input_parameter< std::string >::type x(xSEXP); 154 | rcpp_result_gen = Rcpp::wrap(context_extents(cc, x)); 155 | return rcpp_result_gen; 156 | END_RCPP_RETURN_ERROR 157 | } 158 | RcppExport SEXP _gdtools_context_extents(SEXP ccSEXP, SEXP xSEXP) { 159 | SEXP rcpp_result_gen; 160 | { 161 | Rcpp::RNGScope rcpp_rngScope_gen; 162 | rcpp_result_gen = PROTECT(_gdtools_context_extents_try(ccSEXP, xSEXP)); 163 | } 164 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 165 | if (rcpp_isInterrupt_gen) { 166 | UNPROTECT(1); 167 | Rf_onintr(); 168 | } 169 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 170 | if (rcpp_isLongjump_gen) { 171 | Rcpp::internal::resumeJump(rcpp_result_gen); 172 | } 173 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 174 | if (rcpp_isError_gen) { 175 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 176 | UNPROTECT(1); 177 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 178 | } 179 | UNPROTECT(1); 180 | return rcpp_result_gen; 181 | } 182 | // raster_to_str 183 | std::string raster_to_str(std::vector raster, int w, int h, double width, double height, int interpolate); 184 | static SEXP _gdtools_raster_to_str_try(SEXP rasterSEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP) { 185 | BEGIN_RCPP 186 | Rcpp::RObject rcpp_result_gen; 187 | Rcpp::traits::input_parameter< std::vector >::type raster(rasterSEXP); 188 | Rcpp::traits::input_parameter< int >::type w(wSEXP); 189 | Rcpp::traits::input_parameter< int >::type h(hSEXP); 190 | Rcpp::traits::input_parameter< double >::type width(widthSEXP); 191 | Rcpp::traits::input_parameter< double >::type height(heightSEXP); 192 | Rcpp::traits::input_parameter< int >::type interpolate(interpolateSEXP); 193 | rcpp_result_gen = Rcpp::wrap(raster_to_str(raster, w, h, width, height, interpolate)); 194 | return rcpp_result_gen; 195 | END_RCPP_RETURN_ERROR 196 | } 197 | RcppExport SEXP _gdtools_raster_to_str(SEXP rasterSEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP) { 198 | SEXP rcpp_result_gen; 199 | { 200 | Rcpp::RNGScope rcpp_rngScope_gen; 201 | rcpp_result_gen = PROTECT(_gdtools_raster_to_str_try(rasterSEXP, wSEXP, hSEXP, widthSEXP, heightSEXP, interpolateSEXP)); 202 | } 203 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 204 | if (rcpp_isInterrupt_gen) { 205 | UNPROTECT(1); 206 | Rf_onintr(); 207 | } 208 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 209 | if (rcpp_isLongjump_gen) { 210 | Rcpp::internal::resumeJump(rcpp_result_gen); 211 | } 212 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 213 | if (rcpp_isError_gen) { 214 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 215 | UNPROTECT(1); 216 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 217 | } 218 | UNPROTECT(1); 219 | return rcpp_result_gen; 220 | } 221 | // raster_to_file 222 | int raster_to_file(std::vector raster, int w, int h, double width, double height, int interpolate, std::string filename); 223 | static SEXP _gdtools_raster_to_file_try(SEXP rasterSEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP, SEXP filenameSEXP) { 224 | BEGIN_RCPP 225 | Rcpp::RObject rcpp_result_gen; 226 | Rcpp::traits::input_parameter< std::vector >::type raster(rasterSEXP); 227 | Rcpp::traits::input_parameter< int >::type w(wSEXP); 228 | Rcpp::traits::input_parameter< int >::type h(hSEXP); 229 | Rcpp::traits::input_parameter< double >::type width(widthSEXP); 230 | Rcpp::traits::input_parameter< double >::type height(heightSEXP); 231 | Rcpp::traits::input_parameter< int >::type interpolate(interpolateSEXP); 232 | Rcpp::traits::input_parameter< std::string >::type filename(filenameSEXP); 233 | rcpp_result_gen = Rcpp::wrap(raster_to_file(raster, w, h, width, height, interpolate, filename)); 234 | return rcpp_result_gen; 235 | END_RCPP_RETURN_ERROR 236 | } 237 | RcppExport SEXP _gdtools_raster_to_file(SEXP rasterSEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP, SEXP filenameSEXP) { 238 | SEXP rcpp_result_gen; 239 | { 240 | Rcpp::RNGScope rcpp_rngScope_gen; 241 | rcpp_result_gen = PROTECT(_gdtools_raster_to_file_try(rasterSEXP, wSEXP, hSEXP, widthSEXP, heightSEXP, interpolateSEXP, filenameSEXP)); 242 | } 243 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 244 | if (rcpp_isInterrupt_gen) { 245 | UNPROTECT(1); 246 | Rf_onintr(); 247 | } 248 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 249 | if (rcpp_isLongjump_gen) { 250 | Rcpp::internal::resumeJump(rcpp_result_gen); 251 | } 252 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 253 | if (rcpp_isError_gen) { 254 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 255 | UNPROTECT(1); 256 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 257 | } 258 | UNPROTECT(1); 259 | return rcpp_result_gen; 260 | } 261 | // raster_png_ 262 | bool raster_png_(CharacterVector raster_, int w, int h, double width, double height, int interpolate, std::string filename); 263 | static SEXP _gdtools_raster_png__try(SEXP raster_SEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP, SEXP filenameSEXP) { 264 | BEGIN_RCPP 265 | Rcpp::RObject rcpp_result_gen; 266 | Rcpp::traits::input_parameter< CharacterVector >::type raster_(raster_SEXP); 267 | Rcpp::traits::input_parameter< int >::type w(wSEXP); 268 | Rcpp::traits::input_parameter< int >::type h(hSEXP); 269 | Rcpp::traits::input_parameter< double >::type width(widthSEXP); 270 | Rcpp::traits::input_parameter< double >::type height(heightSEXP); 271 | Rcpp::traits::input_parameter< int >::type interpolate(interpolateSEXP); 272 | Rcpp::traits::input_parameter< std::string >::type filename(filenameSEXP); 273 | rcpp_result_gen = Rcpp::wrap(raster_png_(raster_, w, h, width, height, interpolate, filename)); 274 | return rcpp_result_gen; 275 | END_RCPP_RETURN_ERROR 276 | } 277 | RcppExport SEXP _gdtools_raster_png_(SEXP raster_SEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP, SEXP filenameSEXP) { 278 | SEXP rcpp_result_gen; 279 | { 280 | Rcpp::RNGScope rcpp_rngScope_gen; 281 | rcpp_result_gen = PROTECT(_gdtools_raster_png__try(raster_SEXP, wSEXP, hSEXP, widthSEXP, heightSEXP, interpolateSEXP, filenameSEXP)); 282 | } 283 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 284 | if (rcpp_isInterrupt_gen) { 285 | UNPROTECT(1); 286 | Rf_onintr(); 287 | } 288 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 289 | if (rcpp_isLongjump_gen) { 290 | Rcpp::internal::resumeJump(rcpp_result_gen); 291 | } 292 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 293 | if (rcpp_isError_gen) { 294 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 295 | UNPROTECT(1); 296 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 297 | } 298 | UNPROTECT(1); 299 | return rcpp_result_gen; 300 | } 301 | // base64_raster_encode 302 | std::string base64_raster_encode(CharacterVector raster_, int w, int h, double width, double height, int interpolate); 303 | static SEXP _gdtools_base64_raster_encode_try(SEXP raster_SEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP) { 304 | BEGIN_RCPP 305 | Rcpp::RObject rcpp_result_gen; 306 | Rcpp::traits::input_parameter< CharacterVector >::type raster_(raster_SEXP); 307 | Rcpp::traits::input_parameter< int >::type w(wSEXP); 308 | Rcpp::traits::input_parameter< int >::type h(hSEXP); 309 | Rcpp::traits::input_parameter< double >::type width(widthSEXP); 310 | Rcpp::traits::input_parameter< double >::type height(heightSEXP); 311 | Rcpp::traits::input_parameter< int >::type interpolate(interpolateSEXP); 312 | rcpp_result_gen = Rcpp::wrap(base64_raster_encode(raster_, w, h, width, height, interpolate)); 313 | return rcpp_result_gen; 314 | END_RCPP_RETURN_ERROR 315 | } 316 | RcppExport SEXP _gdtools_base64_raster_encode(SEXP raster_SEXP, SEXP wSEXP, SEXP hSEXP, SEXP widthSEXP, SEXP heightSEXP, SEXP interpolateSEXP) { 317 | SEXP rcpp_result_gen; 318 | { 319 | Rcpp::RNGScope rcpp_rngScope_gen; 320 | rcpp_result_gen = PROTECT(_gdtools_base64_raster_encode_try(raster_SEXP, wSEXP, hSEXP, widthSEXP, heightSEXP, interpolateSEXP)); 321 | } 322 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 323 | if (rcpp_isInterrupt_gen) { 324 | UNPROTECT(1); 325 | Rf_onintr(); 326 | } 327 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 328 | if (rcpp_isLongjump_gen) { 329 | Rcpp::internal::resumeJump(rcpp_result_gen); 330 | } 331 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 332 | if (rcpp_isError_gen) { 333 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 334 | UNPROTECT(1); 335 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 336 | } 337 | UNPROTECT(1); 338 | return rcpp_result_gen; 339 | } 340 | // base64_file_encode 341 | std::string base64_file_encode(std::string filename); 342 | static SEXP _gdtools_base64_file_encode_try(SEXP filenameSEXP) { 343 | BEGIN_RCPP 344 | Rcpp::RObject rcpp_result_gen; 345 | Rcpp::traits::input_parameter< std::string >::type filename(filenameSEXP); 346 | rcpp_result_gen = Rcpp::wrap(base64_file_encode(filename)); 347 | return rcpp_result_gen; 348 | END_RCPP_RETURN_ERROR 349 | } 350 | RcppExport SEXP _gdtools_base64_file_encode(SEXP filenameSEXP) { 351 | SEXP rcpp_result_gen; 352 | { 353 | Rcpp::RNGScope rcpp_rngScope_gen; 354 | rcpp_result_gen = PROTECT(_gdtools_base64_file_encode_try(filenameSEXP)); 355 | } 356 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 357 | if (rcpp_isInterrupt_gen) { 358 | UNPROTECT(1); 359 | Rf_onintr(); 360 | } 361 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 362 | if (rcpp_isLongjump_gen) { 363 | Rcpp::internal::resumeJump(rcpp_result_gen); 364 | } 365 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 366 | if (rcpp_isError_gen) { 367 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 368 | UNPROTECT(1); 369 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 370 | } 371 | UNPROTECT(1); 372 | return rcpp_result_gen; 373 | } 374 | // base64_string_encode 375 | std::string base64_string_encode(std::string string); 376 | static SEXP _gdtools_base64_string_encode_try(SEXP stringSEXP) { 377 | BEGIN_RCPP 378 | Rcpp::RObject rcpp_result_gen; 379 | Rcpp::traits::input_parameter< std::string >::type string(stringSEXP); 380 | rcpp_result_gen = Rcpp::wrap(base64_string_encode(string)); 381 | return rcpp_result_gen; 382 | END_RCPP_RETURN_ERROR 383 | } 384 | RcppExport SEXP _gdtools_base64_string_encode(SEXP stringSEXP) { 385 | SEXP rcpp_result_gen; 386 | { 387 | Rcpp::RNGScope rcpp_rngScope_gen; 388 | rcpp_result_gen = PROTECT(_gdtools_base64_string_encode_try(stringSEXP)); 389 | } 390 | Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); 391 | if (rcpp_isInterrupt_gen) { 392 | UNPROTECT(1); 393 | Rf_onintr(); 394 | } 395 | bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); 396 | if (rcpp_isLongjump_gen) { 397 | Rcpp::internal::resumeJump(rcpp_result_gen); 398 | } 399 | Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); 400 | if (rcpp_isError_gen) { 401 | SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); 402 | UNPROTECT(1); 403 | Rf_error(CHAR(rcpp_msgSEXP_gen)); 404 | } 405 | UNPROTECT(1); 406 | return rcpp_result_gen; 407 | } 408 | // version_freetype 409 | Rcpp::List version_freetype(); 410 | RcppExport SEXP _gdtools_version_freetype() { 411 | BEGIN_RCPP 412 | Rcpp::RObject rcpp_result_gen; 413 | Rcpp::RNGScope rcpp_rngScope_gen; 414 | rcpp_result_gen = Rcpp::wrap(version_freetype()); 415 | return rcpp_result_gen; 416 | END_RCPP 417 | } 418 | // version_cairo_ 419 | Rcpp::CharacterVector version_cairo_(); 420 | RcppExport SEXP _gdtools_version_cairo_() { 421 | BEGIN_RCPP 422 | Rcpp::RObject rcpp_result_gen; 423 | Rcpp::RNGScope rcpp_rngScope_gen; 424 | rcpp_result_gen = Rcpp::wrap(version_cairo_()); 425 | return rcpp_result_gen; 426 | END_RCPP 427 | } 428 | 429 | // validate (ensure exported C++ functions exist before calling them) 430 | static int _gdtools_RcppExport_validate(const char* sig) { 431 | static std::set signatures; 432 | if (signatures.empty()) { 433 | signatures.insert("XPtrCairoContext(*context_create)()"); 434 | signatures.insert("bool(*context_set_font)(XPtrCairoContext,std::string,double,bool,bool,std::string)"); 435 | signatures.insert("FontMetric(*context_extents)(XPtrCairoContext,std::string)"); 436 | signatures.insert("std::string(*raster_to_str)(std::vector,int,int,double,double,int)"); 437 | signatures.insert("int(*raster_to_file)(std::vector,int,int,double,double,int,std::string)"); 438 | signatures.insert("bool(*raster_png_)(CharacterVector,int,int,double,double,int,std::string)"); 439 | signatures.insert("std::string(*base64_raster_encode)(CharacterVector,int,int,double,double,int)"); 440 | signatures.insert("std::string(*base64_file_encode)(std::string)"); 441 | signatures.insert("std::string(*base64_string_encode)(std::string)"); 442 | } 443 | return signatures.find(sig) != signatures.end(); 444 | } 445 | 446 | // registerCCallable (register entry points for exported C++ functions) 447 | RcppExport SEXP _gdtools_RcppExport_registerCCallable() { 448 | R_RegisterCCallable("gdtools", "_gdtools_context_create", (DL_FUNC)_gdtools_context_create_try); 449 | R_RegisterCCallable("gdtools", "_gdtools_context_set_font", (DL_FUNC)_gdtools_context_set_font_try); 450 | R_RegisterCCallable("gdtools", "_gdtools_context_extents", (DL_FUNC)_gdtools_context_extents_try); 451 | R_RegisterCCallable("gdtools", "_gdtools_raster_to_str", (DL_FUNC)_gdtools_raster_to_str_try); 452 | R_RegisterCCallable("gdtools", "_gdtools_raster_to_file", (DL_FUNC)_gdtools_raster_to_file_try); 453 | R_RegisterCCallable("gdtools", "_gdtools_raster_png_", (DL_FUNC)_gdtools_raster_png__try); 454 | R_RegisterCCallable("gdtools", "_gdtools_base64_raster_encode", (DL_FUNC)_gdtools_base64_raster_encode_try); 455 | R_RegisterCCallable("gdtools", "_gdtools_base64_file_encode", (DL_FUNC)_gdtools_base64_file_encode_try); 456 | R_RegisterCCallable("gdtools", "_gdtools_base64_string_encode", (DL_FUNC)_gdtools_base64_string_encode_try); 457 | R_RegisterCCallable("gdtools", "_gdtools_RcppExport_validate", (DL_FUNC)_gdtools_RcppExport_validate); 458 | return R_NilValue; 459 | } 460 | 461 | static const R_CallMethodDef CallEntries[] = { 462 | {"_gdtools_str_extents_", (DL_FUNC) &_gdtools_str_extents_, 6}, 463 | {"_gdtools_str_metrics_", (DL_FUNC) &_gdtools_str_metrics_, 6}, 464 | {"_gdtools_m_str_extents_", (DL_FUNC) &_gdtools_m_str_extents_, 6}, 465 | {"_gdtools_glyphs_match_", (DL_FUNC) &_gdtools_glyphs_match_, 5}, 466 | {"_gdtools_context_create", (DL_FUNC) &_gdtools_context_create, 0}, 467 | {"_gdtools_context_set_font", (DL_FUNC) &_gdtools_context_set_font, 6}, 468 | {"_gdtools_context_extents", (DL_FUNC) &_gdtools_context_extents, 2}, 469 | {"_gdtools_raster_to_str", (DL_FUNC) &_gdtools_raster_to_str, 6}, 470 | {"_gdtools_raster_to_file", (DL_FUNC) &_gdtools_raster_to_file, 7}, 471 | {"_gdtools_raster_png_", (DL_FUNC) &_gdtools_raster_png_, 7}, 472 | {"_gdtools_base64_raster_encode", (DL_FUNC) &_gdtools_base64_raster_encode, 6}, 473 | {"_gdtools_base64_file_encode", (DL_FUNC) &_gdtools_base64_file_encode, 1}, 474 | {"_gdtools_base64_string_encode", (DL_FUNC) &_gdtools_base64_string_encode, 1}, 475 | {"_gdtools_version_freetype", (DL_FUNC) &_gdtools_version_freetype, 0}, 476 | {"_gdtools_version_cairo_", (DL_FUNC) &_gdtools_version_cairo_, 0}, 477 | {"_gdtools_RcppExport_registerCCallable", (DL_FUNC) &_gdtools_RcppExport_registerCCallable, 0}, 478 | {NULL, NULL, 0} 479 | }; 480 | 481 | RcppExport void R_init_gdtools(DllInfo *dll) { 482 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 483 | R_useDynamicSymbols(dll, FALSE); 484 | } 485 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------