Appendix A — cvd
A.1 Package Dependencies
Load required packages.
\RequirePackage{iftex}
\RequirePackage{xcolor}
\RequirePackage{graphicx}
A.2 Engine Check
Currently only LuaTeX is fully supported.
\sys_if_engine_luatex:F
{
\msg_error:nn { cvd } { luatex-required }
}
\msg_new:nnn { cvd } { luatex-required }
{
LuaTeX~required.\\
This~package~currently~only~works~with~LuaLaTeX.\\
pdfLaTeX~support~is~under~development.
}
A.3 Color Space Enforcement
Force RGB color model for consistent transformations.
\selectcolormodel{rgb}
A.4 Load Lua Module
Next, load the Lua module that implements the CVD transformations. The install_pdf_image_hook function registers a callback that transforms colors in embedded PDF pages (vector graphics only). We also load the Lua File System module for file timestamp checking.
\directlua{lfs = require("lfs"); cvd = require("cvd"); cvd.install_pdf_image_hook()}
A.5 Hook into xcolor
Use xcolor’s hook to transform RGB values before display. This handles text colors, color boxes, and other xcolor-based content.
\cs_set:Npn \XC@bcolor
{
\directlua
{
token.set_macro("current@color",~
cvd.transform_current_color("\luaescapestring{\current@color}"),~
"global")
}
}
A.6 User Commands
A.6.1 \cvdtype
Set the type of color vision deficiency to simulate.
\NewDocumentCommand \cvdtype { m }
{
\directlua { cvd.set_type("#1") }
}
A.6.2 \cvdseverity
Set the severity of the simulation (0.0 to 1.0).
\NewDocumentCommand \cvdseverity { m }
{
\directlua { cvd.set_severity(#1) }
}
A.6.3 \cvdenable
Enable CVD simulation.
\NewDocumentCommand \cvdenable { }
{
\directlua { cvd.enable() }
}
A.6.4 \cvddisable
Disable CVD simulation.
\NewDocumentCommand \cvddisable { }
{
\directlua { cvd.disable() }
}
A.6.5 \cvdincludegraphics
Include a graphics file with CVD transformation applied to raster images.
\tl_new:N \l__cvd_imgpath_tl
\NewDocumentCommand \cvdincludegraphics { O{} m }
{
\tl_set:Nx \l__cvd_imgpath_tl
{
\directlua
{ tex.sprint(cvd.get_image_path("\luaescapestring{#2}")) }
}
\exp_args:No \includegraphics [#1] { \l__cvd_imgpath_tl }
}
A.6.6 \cvddefinecolor
Define a new color by applying CVD transformation to an existing color. Usage:
\tl_new:N \l__cvd_model_tl
\tl_new:N \l__cvd_values_tl
\NewDocumentCommand \cvddefinecolor { O{} m m }
{
% Extract the original color
\extractcolorspecs{#2}{\l__cvd_model_tl}{\l__cvd_values_tl}
% Apply CVD transformation with specified settings
\keys_set:nn { cvd } { #1 }
\cvdenable
% Transform the RGB values directly via Lua
\directlua{
local~values~=~"\luaescapestring{\l__cvd_values_tl}"
local~r,~g,~b~=~values:match("([^,]+),([^,]+),([^,]+)")
r,~g,~b~=~tonumber(r),~tonumber(g),~tonumber(b)
r,~g,~b~=~cvd.transform(r,~g,~b)
token.set_macro("l__cvd_values_tl",~string.format("\csstring\%.6f,\csstring\%.6f,\csstring\%.6f",~r,~g,~b))
}
% Define the color with transformed values
\use:x { \definecolor {#3} { \exp_not:V \l__cvd_model_tl } { \exp_not:V \l__cvd_values_tl } }
\cvddisable
}
A.7 Package Configuration
Define keys for package configuration using . Keys are available both as package load-time options and via the command.
\keys_define:nn { cvd }
{
type .code:n = { \cvdtype{#1} } ,
severity .code:n = { \cvdseverity{#1} } ,
protanopia .code:n = { \cvdtype{protanopia} \cvdseverity{1.0} } ,
deuteranopia .code:n = { \cvdtype{deuteranopia} \cvdseverity{1.0} } ,
tritanopia .code:n = { \cvdtype{tritanopia} \cvdseverity{1.0} } ,
protanomaly .code:n = { \cvdtype{protanopia} \cvdseverity{0.5} } ,
deuteranomaly .code:n = { \cvdtype{deuteranopia} \cvdseverity{0.5} } ,
tritanomaly .code:n = { \cvdtype{tritanopia} \cvdseverity{0.5} } ,
unknown .code:n =
{ \msg_warning:nnx { cvd } { unknown-option } { \l_keys_key_str } }
}
\msg_new:nnn { cvd } { unknown-option }
{ Unknown~option~'#1'. }
\NewDocumentCommand \cvdset { m }
{
\keys_set:nn { cvd } { #1 }
}
\ProcessKeyOptions [ cvd ]