Browse Source

initial commit

master
Bob Rudis 9 years ago
commit
40af15e21a
  1. 4
      .Rbuildignore
  2. 7
      .gitignore
  3. 22
      .travis.yml
  4. 24
      DESCRIPTION
  5. 2
      LICENSE
  6. 8
      NAMESPACE
  7. 48
      R/acov1.R
  8. 110
      R/acov2.R
  9. 5
      R/adobecolor-package.R
  10. 140
      R/adobecolor.R
  11. 111
      R/asev1.R
  12. 79
      R/utils.R
  13. 134
      README.Rmd
  14. 189
      README.md
  15. BIN
      README_files/figure-markdown_github/unnamed-chunk-4-1.png
  16. BIN
      README_files/figure-markdown_github/unnamed-chunk-5-1.png
  17. BIN
      README_files/figure-markdown_github/unnamed-chunk-6-1.png
  18. BIN
      README_files/figure-markdown_github/unnamed-chunk-7-1.png
  19. BIN
      README_files/figure-markdown_github/unnamed-chunk-8-1.png
  20. BIN
      inst/palettes/herbs_and_spice.ase
  21. BIN
      inst/palettes/keep_the_change.ase
  22. BIN
      inst/palettes/omega_nebula.ase
  23. BIN
      inst/palettes/tomorrow_night_eighties.aco
  24. 40
      man/read_aco.Rd
  25. 41
      man/read_ase.Rd
  26. 24
      man/show_palette.Rd
  27. 11
      man/swatches.Rd
  28. 57
      src/float.c
  29. 21
      swatches.Rproj
  30. 2
      tests/test-all.R
  31. 6
      tests/testthat/test-swatches.R

4
.Rbuildignore

@ -0,0 +1,4 @@
^.*\.Rproj$
^\.Rproj\.user$
^\.travis\.yml$
^.*md$

7
.gitignore

@ -0,0 +1,7 @@
.Rproj.user
.Rhistory
.RData
.Rproj
src/*.o
src/*.so
src/*.dll

22
.travis.yml

@ -0,0 +1,22 @@
language: c
before_install:
- curl -OL http://raw.github.com/craigcitro/r-travis/master/scripts/travis-tool.sh
- chmod 755 ./travis-tool.sh
- ./travis-tool.sh bootstrap
install:
- ./travis-tool.sh install_deps
script: ./travis-tool.sh run_tests
on_failure:
- ./travis-tool.sh dump_logs
branches:
except:
- /-expt$/
notifications:
email:
on_success: change
on_failure: change

24
DESCRIPTION

@ -0,0 +1,24 @@
Package: swatches
Type: Package
Title: Read and visualize Adobe color swatch files
Version: 0.2
Date: 2015-03-21
Author: Bob Rudis (@hrbrmstr)
Maintainer: Bob Rudis <bob@rudis.net>
Description: There are numerous places to create and download color
palettes and these are usually shared in Adobe swatch file formats of
some kind. There is also often the need to use standard palettes
developed within an organization to ensure that aesthetics are carried over
into all projects and output. This package makes it possible to use
Adobe swatches in R graphics without the need to transcribe or convert
color values by hand or with other programs.
URL: http://github.com/hrbrmstr/swatches
BugReports: https://github.com/hrbrmstr/swatches/issues
License: MIT + file LICENSE
Imports:
httr
Suggests:
testthat
Depends:
R (>= 3.0.0),
pack

2
LICENSE

@ -0,0 +1,2 @@
YEAR: 2015
COPYRIGHT HOLDER: Bob Rudis

8
NAMESPACE

@ -0,0 +1,8 @@
# Generated by roxygen2 (4.1.0): do not edit by hand
export(read_aco)
export(read_ase)
export(show_palette)
import(httr)
import(pack)
useDynLib(swatches,r_floatraw2numeric)

48
R/acov1.R

@ -0,0 +1,48 @@
decode_aco_v1 <- function(aco, n_colors) {
palette <- sapply(1:n_colors, function(i) {
start <- 5 + (10*(i-1))
colorspace <- b2i(aco[start:(start+1)])
start <- start + 2
w <- b2i(aco[start:(start+1)])
start <- start + 2
x <- b2i(aco[start:(start+1)])
start <- start + 2
y <- b2i(aco[start:(start+1)])
start <- start + 2
z <- b2i(aco[start:(start+1)])
color <- ""
if (colorspace == 0) { # RGB
color <- rgb(w, x, y, maxColorValue=65535)
} else if (colorspace == 1) { # HSB
color <- hsv((w/182.04)/360, ((x/655.35)/360), ((y/655.35)/360))
} else if (colorspace == 2) { # CMYK
color <- cmyk((100-w/655.35), (100-x/655.35), (100-y/655.35), (100-z/655.35))
} else if (colorspace == 7) { # Lab
message("Lab not supported yet")
color <- NA
} else if (colorspace == 8) { # Grayscale
message("Greyscale not supported yet")
color <- w/39.0625
} else if (colorspace == 9) { # Wide CMYK
color <- cmyk(w/100, x/100, y/100, z/100)
} else {
message("Unknown")
color <- NA
}
return(color)
})
return(palette)
}

110
R/acov2.R

@ -0,0 +1,110 @@
decode_aco_v2 <- function(aco, n_colors) {
con <- rawConnection(aco)
on.exit(close(con))
tmp <- readBin(con, "raw", 4, endian="big")
val <- sapply(1:n_colors, function(i) {
parse_aco_v2_block(con)
})
val[!is.na(val)]
}
parse_aco_v2_block <- function(con) {
colorspace <- b2i(readBin(con, "raw", 2, endian="big"))
color <- NA
if (colorspace == 0) { # RGB
w <- b2i(readBin(con, "raw", 2, endian="big"))
x <- b2i(readBin(con, "raw", 2, endian="big"))
y <- b2i(readBin(con, "raw", 2, endian="big"))
z <- b2i(readBin(con, "raw", 2, endian="big"))
color <- rgb(w, x, y, maxColorValue=65535)
} else if (colorspace == 1) { # HSB
w <- b2i(readBin(con, "raw", 2, endian="big"))
x <- b2i(readBin(con, "raw", 2, endian="big"))
y <- b2i(readBin(con, "raw", 2, endian="big"))
z <- b2i(readBin(con, "raw", 2, endian="big"))
color <- hsv((w/182.04)/360, ((x/655.35)/360), ((y/655.35)/360))
} else if (colorspace == 2) { # CMYK
w <- b2i(readBin(con, "raw", 2, endian="big"))
x <- b2i(readBin(con, "raw", 2, endian="big"))
y <- b2i(readBin(con, "raw", 2, endian="big"))
z <- b2i(readBin(con, "raw", 2, endian="big"))
color <- cmyk((100-w/655.35), (100-x/655.35), (100-y/655.35), (100-z/655.35))
} else if (colorspace == 7) { # Lab
w <- b2i(readBin(con, "raw", 2, endian="big"))
x <- readBin(con, "integer", 1, 2, signed=TRUE, endian="big")
y <- readBin(con, "integer", 1, 2, signed=TRUE, endian="big")
z <- b2i(readBin(con, "raw", 2, endian="big"))
# color <- LAB(w/100, x/100, y/100)
color <- NA
message("Lab colors not supported yet")
} else if (colorspace == 8) { # Grayscale
w <- b2i(readBin(con, "raw", 2, endian="big"))
x <- b2i(readBin(con, "raw", 2, endian="big"))
y <- b2i(readBin(con, "raw", 2, endian="big"))
z <- b2i(readBin(con, "raw", 2, endian="big"))
message("Grayscale not supported yet")
color <- w/39.0625
} else if (colorspace == 9) { # Wide CMYK
w <- b2i(readBin(con, "raw", 2, endian="big"))
x <- b2i(readBin(con, "raw", 2, endian="big"))
y <- b2i(readBin(con, "raw", 2, endian="big"))
z <- b2i(readBin(con, "raw", 2, endian="big"))
color <- cmyk(w/100, x/100, y/100, z/100)
} else {
w <- b2i(readBin(con, "raw", 2, endian="big"))
x <- b2i(readBin(con, "raw", 2, endian="big"))
y <- b2i(readBin(con, "raw", 2, endian="big"))
z <- b2i(readBin(con, "raw", 2, endian="big"))
message("Color format unknown")
color <- NA
}
tmp <- readBin(con, "raw", 2, endian="big")
label <- ""
label_length <- b2i(readBin(con, "raw", 2, endian="big")) * 2
if (label_length > 0) {
label <- readBin(con, "raw", label_length-2, endian="big")
label <- rawToChar(label[1:length(label)], multiple=TRUE)
label <- paste(label, sep="", collapse="")
}
names(color) <- label
tmp <- readBin(con, "raw", 2, endian="big")
return(color)
}

5
R/adobecolor-package.R

@ -0,0 +1,5 @@
#' Read Adobe color/swatch files
#' @name swatches
#' @docType package
#' @import pack httr
NULL

140
R/adobecolor.R

@ -0,0 +1,140 @@
#' Read colors from Adobe Color (ACO) files
#'
#' Given a path or URL to an \code{.aco} file, this function will return
#' a named character vector (if color names are present) of hex RGB colors.
#'
#' @param path partial or full file path or URL to an ACO file
#' @param use_names add color names to the vector (defaults to \code{TRUE}). See NOTE
#' @param .verbose show extra information about ACO file processing#' @export
#' @note When using named color palettes in a \code{ggplot2} \code{scale_} context, you
#' must \code{unname} them or set \code{use_names} to \code{FALSE}.
#' Not sure if this is a bug or a deliberate feature in ggplot2. Also, Neither Lab nor
#' greyscale colors are supported.
#' @export
#' @examples \dontrun{
#' # built-in palette
#' eighties <- read_ase(system.file("palettes",
#' "tomorrow_night_eighties.aco", package="swatches"))
#' print(eighties)
#' show_palette(eighties)
#'
#' # from the internet directly
#' tomorrow_night <- read_ase("l.dds.ec/tomorrow-night-aco")
#' print(tomorrow_night)
#' show_palette(tomorrow_night)
#' }
read_aco <- function(path, use_names=TRUE, .verbose=FALSE) {
if (is_url(path)) {
tf <- tempfile()
stop_for_status(GET(path, write_disk(tf)))
path <- tf
}
aco <- readBin(path.expand(path), "raw",
file.info(path.expand(path))$size, endian="big")
version <- unpack("v", aco[2:1])[[1]]
n_colors <- unpack("v", aco[4:3])[[1]]
if (.verbose) {
message("ACO Version: ", version)
message("# Colors: " , n_colors)
}
pal <- NULL
if (version == 1) {
pal <- decode_aco_v1(aco, n_colors)
} else {
pal <- decode_aco_v2(aco, n_colors)
}
if (!use_names) { pal <- unname(pal) }
pal
}
#' Read colors from Adobe Swatch Exchange (ASE) files
#'
#' Given a path or URL to an \code{.ase} file, this function will return
#' a named character vector (if color names are present) of hex RGB colors.
#'
#' @param path partial or full file path or URL to an ASE file
#' @param use_names add color names to the vector (defaults to \code{TRUE}). See NOTE
#' @param .verbose show extra information about ASE file processing
#' @note When using named color palettes in a \code{ggplot2} \code{scale_} context, you
#' must \code{unname} them or set \code{use_names} to \code{FALSE}.
#' Not sure if this is a bug or a deliberate feature in ggplot2. Also, Neither Lab nor
#' greyscale colors are supported.
#' @export
#' @examples
#' \dontrun{
#' # built in palette
#' keep_the_change <- read_ase(system.file("palettes",
#' "keep_the_change.ase", package="swatches"))
#' print(keep_the_change)
#' show_palette(keep_the_change)
#'
#' # from the internet directly
#' github <- "https://github.com/picwellwisher12pk/en_us/raw/master/Swatches/Metal.ase"
#' metal <- read_ase(github)
#' print(metal)
#' show_palette(metal)
#' }
read_ase <- function(path, use_names=TRUE, .verbose=FALSE) {
if (is_url(path)) {
tf <- tempfile()
stop_for_status(GET(path, write_disk(tf)))
path <- tf
}
ase <- readBin(path, "raw",
file.info(path.expand(path))$size, endian="big")
if (unpack("A4", ase[1:4])[[1]] != "ASEF") {
message("Not a valid ASE file")
stop()
}
version <- sprintf("%d.%d", b2i(ase[5:6]), b2i(ase[7:8]))
block_count <- b2li(ase[9:12])
if (.verbose) {
message("ASE Version: ", version)
message("Block count: ", block_count)
}
pal <- decode_ase(ase, block_count)
if (!use_names) { pal <- unname(pal) }
pal
}
#' Display a color palette
#'
#' Given a character vector (hex RGB values), display palette in graphics window.
#'
#' @param palette vector of character hex RGB values
#' @export
#' @examples
#' \dontrun{
#' # built in palette
#' keep_the_change <- read_ase(system.file("palettes",
#' "keep_the_change.ase", package="swatches"))
#' print(keep_the_change)
#' show_palette(keep_the_change)
#' }
show_palette <- function(palette) {
n <- length(palette)
if (length(palette > 0)) {
image(1:n, 1, as.matrix(1:n), col = palette,
xlab = "", ylab = "", xaxt = "n", yaxt = "n",
bty = "n")
}
}

111
R/asev1.R

@ -0,0 +1,111 @@
GROUP_START <- 0xc001
GROUP_END <- 0xc002
COLOR_START <- 0x0001
decode_ase <- function(ase, block_count) {
con <- rawConnection(ase)
on.exit(close(con))
tmp <- readBin(con, "raw", 12, endian="big")
val <- sapply(1:block_count, function(i) {
parse_block(con)
})
val[!is.na(val)]
}
parse_block <- function(con) {
block_type <- try(readBin(con, "raw", 2, endian="big"))
if (!inherits(block_type, "try-error")) {
block_type <- b2i(block_type)
if (block_type == COLOR_START) {
block_length <- b2li(readBin(con, "raw", 4, endian="big"))
data <- readBin(con, "raw", block_length, endian="big")
label_length <- b2i(data[1:2]) * 2
label <- data[3:(3+label_length)]
label <- rawToChar(label[1:(length(label)-1)], multiple=TRUE)
label <- paste(label, sep="", collapse="")
color_data <- try(data[3+label_length:length(data)])
if (!inherits(color_data, "try-error")) {
color_mode <- gsub("\ +$", "", rawToChar(color_data[1:4]))
color <- NA
if (color_mode == "RGB") {
R <- b2f(color_data[5:8])
G <- b2f(color_data[9:12])
B <- b2f(color_data[13:16])
color <- as.character(rgb(R, G, B))
} else if (color_mode == "CMYK") {
C <- b2f(color_data[5:8])
M <- b2f(color_data[9:12])
Y <- b2f(color_data[13:16])
K <- b2f(color_data[17:20])
color <- as.character(cmyk(C*100, M*100, Y*100, K*100))
} else if (color_mode == "LAB") {
message("LAB")
L <- b2f(color_data[5:8])
A <- b2f(color_data[9:12])
B <- b2f(color_data[13:16])
color <- list(L, A, B)
} else if (color_mode == "Grey") {
message("Grey")
G <- b2f(color_data[5:8])
color <- G
}
color_type <- b2i(color_data[(length(color_data)-1):length(color_data)])
names(color) <- label
return(color)
}
} else if (block_type == GROUP_START) {
block_length <- b2li(readBin(con, "raw", 4, endian="big"))
data <- readBin(con, "raw", block_length, endian="big")
label_length <- b2i(data[1:2]) * 2
label <- data[3:(3+label_length)]
label <- rawToChar(label[1:(length(label)-1)], multiple=TRUE)
label <- paste(label, sep="", collapse="")
color_data <- try(data[3+label_length:length(data)])
return(NA)
} else if (block_type == GROUP_END) {
tmp <- readBin(con, "raw", 4, endian="big")
return(NA)
} else {
message("Invalid block type [", block_type, "]. Possible corrupted ASE file")
return(NA)
}
}
}

79
R/utils.R

@ -0,0 +1,79 @@
cmyk <- function(C, M, Y, K) {
C <- C / 100.0
M <- M / 100.0
Y <- Y / 100.0
K <- K / 100.0
n.c <- (C * (1-K) + K)
n.m <- (M * (1-K) + K)
n.y <- (Y * (1-K) + K)
r.col <- ceiling(255 * (1-n.c))
g.col <- ceiling(255 * (1-n.m))
b.col <- ceiling(255 * (1-n.y))
return(sprintf("#%02s%02s%02s", as.hexmode(r.col),
as.hexmode(g.col), as.hexmode(b.col)))
}
b2i <- function(two_bytes) {
as.numeric(unpack("v", two_bytes[2:1]))
}
b2li <- function(four_bytes) {
as.numeric(unpack("V", four_bytes[c(4,3,2,1)]))
}
b2f <- function(four_bytes) {
floatraw2numeric(four_bytes[c(4,3,2,1)])
}
is_url <-function(x) { grepl("www.|http:|https:", x) }
#' @useDynLib swatches r_floatraw2numeric
floatraw2numeric <- function(x) {
stopifnot(is.raw(x))
stopifnot(length(x) >= 4)
.Call(r_floatraw2numeric, x)
}
# #' @export
# lab2rgb <- function(L, A, B) {
#
# R <- G <- B <- 0
#
# vY <- (L + 16.0) / 116.0
# vX <- (A / 500.0) + vY
# vZ <- vY - (B / 200.0)
#
# if (vY^3 > 0.008856) { vY <- vY^3 } else { vY <- ( vY - 16.0 / 116.0 ) / 7.787 }
# if (vX^3 > 0.008856) { vX <- vX^3 } else { vX <- ( vX - 16.0 / 116.0 ) / 7.787 }
# if (vZ^3 > 0.008856) { vZ <- vZ^3 } else { vZ <- ( vZ - 16.0 / 116.0 ) / 7.787 }
#
# X <- 95.047 * vX
# Y <- 100.000 * vY
# Z <- 108.883 * vZ
#
# vX <- X / 100.0
# vY <- Y / 100.0
# vZ <- Z / 100.0
#
# vR <- (vX * 3.2406) + (vY * -1.5372) + (vZ * -0.4986)
# vG <- (vX * -0.9689) + (vY * 1.8758) + (vZ * 0.0415)
# vB <- (vX * 0.0557) + (vY * -0.2040) + (vZ * 1.0570)
#
# if (vR > 0.0031308) { vR <- (1.055 * vR^(1/2.4)) - 0.55 } else { vR <- 12.92 * vR }
# if (vG > 0.0031308) { vG <- (1.055 * vG^(1/2.4)) - 0.55 } else { vG <- 12.92 * vG }
# if (vB > 0.0031308) { vB <- (1.055 * vB^(1/2.4)) - 0.55 } else { vB <- 12.92 * vB }
#
# message(vR, " ", vG, " ", vB)
#
# return(rgb(abs(vR), abs(vG), abs(vB)))
# #
# # R <- vR * 255.0
# # G <- vG * 255.0
# # B <- vB * 255.0
#
# }

134
README.Rmd

@ -0,0 +1,134 @@
---
title: "README"
author: "Bob Rudis"
date: March 21, 2015
output:
md_document:
variant: markdown_github
---
[![Build Status](https://travis-ci.org/hrbrmstr/swatches.svg)](https://travis-ci.org/hrbrmstr/swatches)
swatches is a package to read (and eventually write) Adobe color (ASE/ACO) files
In _Envisioning Information_, Edward Tufte says _"&hellip;avoiding catastrophe becomes the first
principle in bringing color to information: Above all, do no harm."_ R users gain a quick upper hand
in adhering to this "do no harm" thanks to sane defaults in `ggplot2` and packages like [ggthemes](http://cran.r-project.org/web/packages/ggthemes/index.html) and
[RColorBrewer](http://cran.r-project.org/web/packages/RColorBrewer/index.html) that enable use of established, good color palettes.
If you do visualization work in conjunction with a design shop or organization that establishes their own
palettes and themes there will often be standard palettes that must be adhered to. These are usually stored and
shared in some type of Adobe swatch file format. There are also many sites like [Adobe Color CC](https://color.adobe.com/) and
[COLOUR Lovers](http://www.colourlovers.com/) where folks can create and share color palettes.
This package enables you to use the colors straight from `.ase` or `.aso` files and avoid the cutting/pasting of hex codes
or using color pickers to extract the color information. You can read these swatch files directly from the internet and/or
include the files directly in your R projects. This will make it easier to modify a resource versus change code.
NOTE that just beacuse an ASE or ACO file exists on the internet does _not_ mean that it will let you "do no harm". You
still need to use good judgement from knowledge/experience (or advice from experts) to ensure you are using colors effectively.
This package just opens up the world of colors in R a little bit more.
The following functions are implemented:
- `read_aco` : Read colors from Adobe Color (ACO) files
- `read_ase` : Read colors from Adobe Swatch Exchange (ASE) files
- `show_palette` :Display a color palette
### TODO
- Grayscale support (just need to find or gen Grayscale ASE/ACO files, if you have a few please hook me up)
- LAB support (could use some help with this)
- Writing out ACO or ASE files (not sure this is needed, tho)
### News
- Version `0.1` released
- Version `0.2` released : ACO v2 support
### Installation
```{r eval=FALSE}
devtools::install_github("hrbrmstr/swatches")
```
```{r echo=FALSE, message=FALSE, warning=FALSE, error=FALSE}
options(width=80)
```
### Usage & Exposition
```{r}
library(swatches)
# current verison
packageVersion("swatches")
```
One good source for palettes is the ["Most Popular" section](https://color.adobe.com/explore/most-popular/?time=all) on
Adobe Color CC. If you use the Adobe ecosystem, you can sync ASE palette files directly locally or download them directly
(registration required).
![](https://www.evernote.com/shard/s1/sh/357686a4-3688-4f01-887d-463a259fc5ec/a83815d1519e5db35f80f5e5c52e15e3/deep/0/Explore---Most-Popular---Adobe-Color-CC.png)
The "Herbs and Spice" and "Keep the Change" palettes are kinda nifty, and also included in this package (since Adobe has yet to
release the new API for the color site for automatic downloading). We can take a quick look at both of them. Here they are from the web site:
![](http://note.io/1I51HRo)
And, there they are via this package:
```{r fig.height=2.5}
herbs_and_spice <- read_ase(system.file("palettes", "herbs_and_spice.ase", package="swatches"))
print(herbs_and_spice)
show_palette(herbs_and_spice)
```
```{r fig.height=2.5}
keep_the_change <- read_ase(system.file("palettes", "keep_the_change.ase", package="swatches"))
print(keep_the_change)
show_palette(keep_the_change)
```
As said earlier, you can also read directly from a URL. Here is a "metal" palette ripped straight [from github](https://github.com/picwellwisher12pk/en_us/):
```{r fig.height=2.5}
metal <- read_ase("https://github.com/picwellwisher12pk/en_us/raw/master/Swatches/Metal.ase")
print(metal)
show_palette(metal)
```
As you can see, this "metal" palette actually had named colors (albeit bland, CMYK value names).
Some palettes, like the Omega Nebula (CC-BY-SA [davidgav](http://www.colourlovers.com/lover/davidgav/loveNote)) one included with the package, have license restrictions (the mind _boggles_), so be aware of that when blatantly using others' designs without attribution. David's palette has much better names:
```{r fig.height=2.5}
omega_nebula <- read_ase(system.file("palettes", "omega_nebula.ase", package="swatches"))
print(omega_nebula)
show_palette(omega_nebula)
```
For some reason (I haven't poked at the source code yet or talked to @hadleywickham), ggplot `scale_*_manual` (color/fill)'s do _not_
like named color vectors. So you need to use `unname` (or `use_names=FALSE` in `read_ase` or `read_aco`) before using them as `values`:
```{r fig.height=4}
library(ggplot2)
gg <- ggplot(mtcars, aes(x=mpg, y=disp))
gg <- gg + geom_point(aes(col=factor(gear)), size=3)
gg <- gg + scale_color_manual(values=unname(keep_the_change))
gg <- gg + theme_bw()
gg
```
### Test Results
```{r}
library(swatches)
library(testthat)
date()
test_dir("tests/")
```

189
README.md

@ -0,0 +1,189 @@
[![Build Status](https://travis-ci.org/hrbrmstr/swatches.svg)](https://travis-ci.org/hrbrmstr/swatches)
swatches is a package to read (and eventually write) Adobe color (ASE/ACO) files
In *Envisioning Information*, Edward Tufte says *"…avoiding catastrophe becomes the first principle in bringing color to information: Above all, do no harm."* R users gain a quick upper hand in adhering to this "do no harm" thanks to sane defaults in `ggplot2` and packages like [ggthemes](http://cran.r-project.org/web/packages/ggthemes/index.html) and [RColorBrewer](http://cran.r-project.org/web/packages/RColorBrewer/index.html) that enable use of established, good color palettes.
If you do visualization work in conjunction with a design shop or organization that establishes their own palettes and themes there will often be standard palettes that must be adhered to. These are usually stored and shared in some type of Adobe swatch file format. There are also many sites like [Adobe Color CC](https://color.adobe.com/) and [COLOUR Lovers](http://www.colourlovers.com/) where folks can create and share color palettes.
This package enables you to use the colors straight from `.ase` or `.aso` files and avoid the cutting/pasting of hex codes or using color pickers to extract the color information. You can read these swatch files directly from the internet and/or include the files directly in your R projects. This will make it easier to modify a resource versus change code.
NOTE that just beacuse an ASE or ACO file exists on the internet does *not* mean that it will let you "do no harm". You still need to use good judgement from knowledge/experience (or advice from experts) to ensure you are using colors effectively. This package just opens up the world of colors in R a little bit more.
The following functions are implemented:
- `read_aco` : Read colors from Adobe Color (ACO) files
- `read_ase` : Read colors from Adobe Swatch Exchange (ASE) files
- `show_palette` :Display a color palette
### TODO
- Grayscale support (just need to find or gen Grayscale ASE/ACO files, if you have a few please hook me up)
- LAB support (could use some help with this)
- Writing out ACO or ASE files (not sure this is needed, tho)
### News
- Version `0.1` released
- Version `0.2` released : ACO v2 support
### Installation
``` r
devtools::install_github("hrbrmstr/swatches")
```
### Usage & Exposition
``` r
library(swatches)
```
## Loading required package: pack
``` r
# current verison
packageVersion("swatches")
```
## [1] '0.2'
One good source for palettes is the ["Most Popular" section](https://color.adobe.com/explore/most-popular/?time=all) on Adobe Color CC. If you use the Adobe ecosystem, you can sync ASE palette files directly locally or download them directly (registration required).
![](https://www.evernote.com/shard/s1/sh/357686a4-3688-4f01-887d-463a259fc5ec/a83815d1519e5db35f80f5e5c52e15e3/deep/0/Explore---Most-Popular---Adobe-Color-CC.png)
The "Herbs and Spice" and "Keep the Change" palettes are kinda nifty, and also included in this package (since Adobe has yet to release the new API for the color site for automatic downloading). We can take a quick look at both of them. Here they are from the web site:
![](http://note.io/1I51HRo)
And, there they are via this package:
``` r
herbs_and_spice <- read_ase(system.file("palettes", "herbs_and_spice.ase", package="swatches"))
print(herbs_and_spice)
```
##
## "#5A1F00" "#D1570D" "#FDE792" "#477725" "#A9CC66"
``` r
show_palette(herbs_and_spice)
```
![](README_files/figure-markdown_github/unnamed-chunk-4-1.png)
``` r
keep_the_change <- read_ase(system.file("palettes", "keep_the_change.ase", package="swatches"))
print(keep_the_change)
```
##
## "#6B0C22" "#D9042B" "#F4CB89" "#588C8C" "#011C26"
``` r
show_palette(keep_the_change)
```
![](README_files/figure-markdown_github/unnamed-chunk-5-1.png)
As said earlier, you can also read directly from a URL. Here is a "metal" palette ripped straight [from github](https://github.com/picwellwisher12pk/en_us/):
``` r
metal <- read_ase("https://github.com/picwellwisher12pk/en_us/raw/master/Swatches/Metal.ase")
print(metal)
```
## C=0 M=0 Y=30 K=0 C=2 M=20 Y=94 K=0 C=0 M=6 Y=47 K=0
## "#ffffb3" "#fbcc0f" "#feef89"
## C=20 M=40 Y=96 K=7 C=16 M=32 Y=82 K=5 C=4 M=14 Y=60 K=8
## "#bf9009" "#cba62c" "#e2cc5e"
## C=1 M=19 Y=90 K=0 C=0 M=5 Y=42 K=5 C=8 M=4 Y=3 K=27
## "#fccf1b" "#f2e78c" "#acb3b5"
## C=17 M=8 Y=5 K=39 C=2 M=0 Y=4 K=16 C=6 M=7 Y=4 K=22
## "#829094" "#d2d7ce" "#bdbbc1"
## C=11 M=13 Y=8 K=38 C=8 M=9 Y=6 K=28 C=3 M=4 Y=3 K=14
## "#8d8a91" "#a9a7ad" "#d3d2d5"
## C=1 M=1 Y=1 K=7 C=4 M=3 Y=3 K=7 C=18 M=8 Y=10 K=48
## "#ececed" "#e3e6e6" "#6e7c79"
## C=10 M=5 Y=6 K=24 C=17 M=11 Y=13 K=0 C=31 M=24 Y=25 K=0
## "#b0b9b7" "#d5e3de" "#b0c4c0"
## C=64 M=47 Y=52 K=19 C=51 M=37 Y=40 K=4 C=71 M=53 Y=57 K=32
## "#4a6e64" "#7a9c94" "#33524b"
## C=0 M=7 Y=24 K=5 C=18 M=43 Y=89 K=7 C=1 M=12 Y=50 K=6 1
## "#f3e3bb" "#c4871b" "#edd378"
## C=21 M=49 Y=100 K=7 C=16 M=38 Y=79 K=6 C=0 M=19 Y=54 K=8
## "#bd7a00" "#ca9434" "#ebbf6c"
## C=0 M=5 Y=15 K=4 C=1 M=12 Y=50 K=6 C=1 M=8 Y=32 K=5
## "#f5e9d1" "#edd378" "#f1dea4"
## C=6 M=4 Y=3 K=39 C=5 M=4 Y=2 K=29 1 C=3 M=3 Y=1 K=16
## "#939697" "#acadb0" "#d1d1d4"
## C=39 M=83 Y=92 K=42 C=22 M=57 Y=86 K=23 1 C=0 M=52 Y=86 K=29
## "#5a190d" "#99551c" "#b6581a"
## C=0 M=15 Y=36 K=9 1 C=6 M=39 Y=74 K=22 1 C=25 M=43 Y=65 K=17
## "#e9c695" "#ba7934" "#9f794b"
## C=14 M=32 Y=51 K=11 C=0 M=21 Y=35 K=17 C=33 M=31 Y=46 K=11
## "#c49a6f" "#d4a88a" "#999c7a"
## C=76 M=41 Y=68 K=35 C=67 M=42 Y=54 K=5 C=78 M=45 Y=56 K=3
## "#296335" "#518d70" "#36876c"
## C=0 M=0 Y=0 K=100 C=0 M=0 Y=0 K=78 1 C=0 M=0 Y=0 K=42 1
## "#000000" "#3a3a3a" "#949494"
## C=0 M=0 Y=0 K=26 1 C=0 M=0 Y=0 K=66 1 C=0 M=0 Y=0 K=10 1
## "#bdbdbd" "#565656" "#e6e6e6"
## C=0 M=0 Y=0 K=0
## "#ffffff"
``` r
show_palette(metal)
```
![](README_files/figure-markdown_github/unnamed-chunk-6-1.png)
As you can see, this "metal" palette actually had named colors (albeit bland, CMYK value names).
Some palettes, like the Omega Nebula (CC-BY-SA [davidgav](http://www.colourlovers.com/lover/davidgav/loveNote)) one included with the package, have license restrictions (the mind *boggles*), so be aware of that when blatantly using others' designs without attribution. David's palette has much better names:
``` r
omega_nebula <- read_ase(system.file("palettes", "omega_nebula.ase", package="swatches"))
print(omega_nebula)
```
## distance between Pale Clay Snow forest III
## "#9D7E79" "#CCAC95" "#9A947C" "#748B83"
## Aqua Smoke
## "#5B756C"
``` r
show_palette(omega_nebula)
```
![](README_files/figure-markdown_github/unnamed-chunk-7-1.png)
For some reason (I haven't poked at the source code yet or talked to @hadleywickham), ggplot `scale_*_manual` (color/fill)'s do *not* like named color vectors. So you need to use `unname` (or `use_names=FALSE` in `read_ase` or `read_aco`) before using them as `values`:
``` r
library(ggplot2)
gg <- ggplot(mtcars, aes(x=mpg, y=disp))
gg <- gg + geom_point(aes(col=factor(gear)), size=3)
gg <- gg + scale_color_manual(values=unname(keep_the_change))
gg <- gg + theme_bw()
gg
```
![](README_files/figure-markdown_github/unnamed-chunk-8-1.png)
### Test Results
``` r
library(swatches)
library(testthat)
date()
```
## [1] "Sat Mar 21 12:30:25 2015"
``` r
test_dir("tests/")
```
## basic functionality :

BIN
README_files/figure-markdown_github/unnamed-chunk-4-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
README_files/figure-markdown_github/unnamed-chunk-5-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
README_files/figure-markdown_github/unnamed-chunk-6-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
README_files/figure-markdown_github/unnamed-chunk-7-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
README_files/figure-markdown_github/unnamed-chunk-8-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
inst/palettes/herbs_and_spice.ase

Binary file not shown.

BIN
inst/palettes/keep_the_change.ase

Binary file not shown.

BIN
inst/palettes/omega_nebula.ase

Binary file not shown.

BIN
inst/palettes/tomorrow_night_eighties.aco

Binary file not shown.

40
man/read_aco.Rd

@ -0,0 +1,40 @@
% Generated by roxygen2 (4.1.0): do not edit by hand
% Please edit documentation in R/adobecolor.R
\name{read_aco}
\alias{read_aco}
\title{Read colors from Adobe Color (ACO) files}
\usage{
read_aco(path, use_names = TRUE, .verbose = FALSE)
}
\arguments{
\item{path}{partial or full file path or URL to an ACO file}
\item{use_names}{add color names to the vector (defaults to \code{TRUE}). See NOTE}
\item{.verbose}{show extra information about ACO file processing#'}
}
\description{
Given a path or URL to an \code{.aco} file, this function will return
a named character vector (if color names are present) of hex RGB colors.
}
\note{
When using named color palettes in a \code{ggplot2} \code{scale_} context, you
must \code{unname} them or set \code{use_names} to \code{FALSE}.
Not sure if this is a bug or a deliberate feature in ggplot2. Also, Neither Lab nor
greyscale colors are supported.
}
\examples{
\dontrun{
# built-in palette
eighties <- read_ase(system.file("palettes",
"tomorrow_night_eighties.aco", package="swatches"))
print(eighties)
show_palette(eighties)
# from the internet directly
tomorrow_night <- read_ase("l.dds.ec/tomorrow-night-aco")
print(tomorrow_night)
show_palette(tomorrow_night)
}
}

41
man/read_ase.Rd

@ -0,0 +1,41 @@
% Generated by roxygen2 (4.1.0): do not edit by hand
% Please edit documentation in R/adobecolor.R
\name{read_ase}
\alias{read_ase}
\title{Read colors from Adobe Swatch Exchange (ASE) files}
\usage{
read_ase(path, use_names = TRUE, .verbose = FALSE)
}
\arguments{
\item{path}{partial or full file path or URL to an ASE file}
\item{use_names}{add color names to the vector (defaults to \code{TRUE}). See NOTE}
\item{.verbose}{show extra information about ASE file processing}
}
\description{
Given a path or URL to an \code{.ase} file, this function will return
a named character vector (if color names are present) of hex RGB colors.
}
\note{
When using named color palettes in a \code{ggplot2} \code{scale_} context, you
must \code{unname} them or set \code{use_names} to \code{FALSE}.
Not sure if this is a bug or a deliberate feature in ggplot2. Also, Neither Lab nor
greyscale colors are supported.
}
\examples{
\dontrun{
# built in palette
keep_the_change <- read_ase(system.file("palettes",
"keep_the_change.ase", package="swatches"))
print(keep_the_change)
show_palette(keep_the_change)
# from the internet directly
github <- "https://github.com/picwellwisher12pk/en_us/raw/master/Swatches/Metal.ase"
metal <- read_ase(github)
print(metal)
show_palette(metal)
}
}

24
man/show_palette.Rd

@ -0,0 +1,24 @@
% Generated by roxygen2 (4.1.0): do not edit by hand
% Please edit documentation in R/adobecolor.R
\name{show_palette}
\alias{show_palette}
\title{Display a color palette}
\usage{
show_palette(palette)
}
\arguments{
\item{palette}{vector of character hex RGB values}
}
\description{
Given a character vector (hex RGB values), display palette in graphics window.
}
\examples{
\dontrun{
# built in palette
keep_the_change <- read_ase(system.file("palettes",
"keep_the_change.ase", package="swatches"))
print(keep_the_change)
show_palette(keep_the_change)
}
}

11
man/swatches.Rd

@ -0,0 +1,11 @@
% Generated by roxygen2 (4.1.0): do not edit by hand
% Please edit documentation in R/adobecolor-package.R
\docType{package}
\name{swatches}
\alias{swatches}
\alias{swatches-package}
\title{Read Adobe color/swatch files}
\description{
Read Adobe color/swatch files
}

57
src/float.c

@ -0,0 +1,57 @@
/** ===========================================================================
** R-Package: rdyncall
** File: src/rutils_float.c
** Description: Utility functions for handling C float data types.
**/
#define USE_RINTERNALS
#include <R.h>
#include <Rinternals.h>
/* Float utils */
SEXP r_as_floatraw(SEXP x) {
SEXP ans;
int i, n;
double *dp;
float *fp;
dp = (double*) REAL(x);
n = LENGTH(x);
if (n < 1) {
error("length of x should be >= 1");
return R_NilValue;
}
ans = PROTECT( Rf_allocVector(RAWSXP, sizeof(float)*n) );
fp = (float*) RAW(ans);
for(i = 0 ; i < n ; ++i )
fp[i] = (float) dp[i];
UNPROTECT(1);
return ans;
}
SEXP r_floatraw2numeric(SEXP x) {
SEXP ans;
int i, n;
float *fp;
double *dp;
fp = (float*) RAW(x);
n = LENGTH(x) / sizeof(float);
ans = PROTECT( Rf_allocVector(REALSXP, n) );
dp = (double*) REAL(ans);
for(i = 0 ; i < n ; ++i )
dp[i] = (double) fp[i];
UNPROTECT(1);
return ans;
}

21
swatches.Rproj

@ -0,0 +1,21 @@
Version: 1.0
RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default
EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8
RnwWeave: Sweave
LaTeX: pdfLaTeX
StripTrailingWhitespace: Yes
BuildType: Package
PackageUseDevtools: Yes
PackageInstallArgs: --no-multiarch --with-keep.source
PackageBuildArgs: --resave-data
PackageRoxygenize: rd,collate,namespace

2
tests/test-all.R

@ -0,0 +1,2 @@
library(testthat)
test_check("swatches")

6
tests/testthat/test-swatches.R

@ -0,0 +1,6 @@
context("basic functionality")
test_that("we can do something", {
#expect_that(some_function(), is_a("data.frame"))
})
Loading…
Cancel
Save