Overview
tc-lib-color provides parsing, conversion, and formatting of color values for web and PDF rendering pipelines.
One normalization layer covers RGB, CMYK, HSL, grayscale, Lab, and spot colors, in both their CSS and their PDF representations. Conversions written ad hoc in three places tend to round differently in all three; here they do not.
Repository and API Docs
- GitHub: https://github.com/tecnickcom/tc-lib-color
- API docs: https://tcpdf.org/docs/srcdoc/tc-lib-color
- Packagist: https://packagist.org/packages/tecnickcom/tc-lib-color
Project Metadata
| Item | Value |
|---|---|
| Namespace | \Com\Tecnick\Color |
| License | GNU LGPL v3 |
Installation
composer require tecnickcom/tc-lib-color
Where It Fits
Use this package whenever rendering needs explicit color conversions and repeatable output across digital and print contexts.
It is a direct dependency of tecnickcom/tc-lib-pdf and is used internally for all color operations during PDF composition.
Color Models
| Model | Class |
|---|---|
| RGB / RGBA | \Com\Tecnick\Color\Model\Rgb |
| HSL / HSLA | \Com\Tecnick\Color\Model\Hsl |
| CMYK | \Com\Tecnick\Color\Model\Cmyk |
| CIE Lab | \Com\Tecnick\Color\Model\Lab |
| Grayscale | \Com\Tecnick\Color\Model\Gray |
Spot colors (Separation) are handled by \Com\Tecnick\Color\Spot, with DeviceCMYK and Lab alternate color spaces for PDF output.
Integration Helpers
- CSS output that parses back to the same color
- PDF and Acrobat JavaScript color output
- Cross-model conversion helpers on all color models
- Named web color lookup (CSS Color Module Level 4 names) and nearest-color matching in sRGB or CIE Lab
Main Classes
| Class | Purpose |
|---|---|
\Com\Tecnick\Color\Web | Named web colors, hex parsing, nearest-color lookup |
\Com\Tecnick\Color\Pdf | PDF color operators, spot color objects, JS color strings |
\Com\Tecnick\Color\Css | CSS color string parsing and normalization |
\Com\Tecnick\Color\Spot | Spot color registry and PDF spot color resource generation |
\Com\Tecnick\Color\ComponentNormalizer | Scaling of parsed component values into the [0..1] range |
Pdf extends Spot extends Web extends Css, so a single object provides the parser, the spot registry and the PDF writer. Each role also has its own interface to type against:
| Interface | Role |
|---|---|
\Com\Tecnick\Color\ColorParserInterface | Color string parsing and named color lookup |
\Com\Tecnick\Color\SpotRegistryInterface | Spot color registration and PDF spot resource output |
\Com\Tecnick\Color\PdfColorWriterInterface | PDF and Acrobat JavaScript color output |
\Com\Tecnick\Color\ExceptionInterface | Common interface of the library exceptions |
Web::getColorObj(), Spot::getSpotColor(), Pdf::getPdfColor() and Pdf::getColorObject() can be overridden, along with the protected parser methods on Css and Spot::resolveSpotColorData(). Every other public method is final.
Supported Color Notations
| Notation | Examples |
|---|---|
| Hexadecimal | #RGB, #RGBA, #RRGGBB, #RRGGBBAA |
| Name | steelblue, color.steelblue, transparent |
| Gray | g(128), g(50%) |
| RGB | rgb(51,102,153), rgb(20% 40% 60%), rgba(51,102,153,0.85), rgb(51 102 153 / 85%) |
| HSL | hsl(210,50%,40%), hsl(210deg 50% 40%), hsla(210,50%,40%,0.85) |
| CMYK | cmyk(67%,33%,0%,40%), cmyka(67,33,0,40,0.85) |
| CIE Lab | lab(41% -2 -25), lab(41 -2 -25 / 0.85) |
| Acrobat JavaScript | ["T"], ["G",0.5], ["RGB",0.2,0.4,0.6], ["CMYK",0.67,0.33,0,0.4] |
Components are separated either by commas or by spaces, not by a mixture of the two, and the alpha channel by a comma in the first form or by a slash in the second. A hue accepts the CSS angle units (deg, grad, rad, turn). Out-of-range components are clamped and hues wrap, as CSS Color Level 4 requires. Anything else is rejected with a \Com\Tecnick\Color\Exception.
g(), cmyk() and cmyka() are notations of this library, not CSS functions, and round-trip through getCssColor() and getColorObj() like the others.
Typed Enums
\Com\Tecnick\Color\ColorModelType is a backed enum listing the supported color models (GRAY, RGB, HSL, CMYK, LAB). Its backing value is the canonical model string returned by the model objects, so it can be used interchangeably with the plain string wherever a model type is accepted. Model::create() builds a model object from an enum case and a component array.
Exceptions
\Com\Tecnick\Color\Exception (a \Exception) signals invalid input. \Com\Tecnick\Color\UnknownComponentException (a \LogicException) signals a component name a model does not define, and is not swallowed by the lenient accessors tryGetColorObj() and getColorObject(). Both implement \Com\Tecnick\Color\ExceptionInterface, so a single catch covers them.
Version 3.0 Changes
Release 3.0 is a breaking change:
Rgb::getCssColor()emitsrgb(255,0,0)andGray::getCssColor()emitsg(128)instead of percentage forms; alpha is capped at four decimals.- The PDF color getters take a trailing
bool $allowSpot = trueargument, and most public methods ofWeb,SpotandPdfarefinal. Model::__construct()is removed from the abstract base: each model validates its own components and raisesUnknownComponentException.- Malformed numbers and mixed comma/space separators are rejected; out-of-range components clamp and hues wrap.
Css::normalizeValue()is concrete and delegates scaling to theComponentNormalizercollaborator.- New API: the role interfaces,
Model::withInvertedColor(),Web::getClosestWebColorByDeltaE(), CSS angle units, slash-alpha and percentage alpha. addSpotLabColor()clamps its range to[-128..127], the spot color accessors return copies, and a spot resource with no PDF object raises instead of being emitted.
How Integration Works
- Instantiate
WeborPdfdepending on target output context. - Parse input color strings (hex, CSS, named, spot) into a color model object.
- Use model output methods to produce CSS strings, PDF operators, or normalized arrays.
- For PDF output, use
Pdf::getPdfColor()to emit the correct PDF color operator.
Web Colors
<?php
require_once __DIR__ . '/vendor/autoload.php';
$web = new \Com\Tecnick\Color\Web();
// Parse a hex color
$rgb = $web->getRgbObjFromHex('#336699');
echo $rgb->getCssColor(); // rgb(51,102,153)
echo $rgb->getRgbHexColor(); // #336699
// Parse a named color
$rgb2 = $web->getRgbObjFromName('cornflowerblue');
echo $rgb2->getCssColor();
// Convert to HSL
$hsl = new \Com\Tecnick\Color\Model\Hsl($rgb->toHslArray());
echo $hsl->getCssColor(); // hsl(210,50%,40%)
// Normalized array (components scaled to 0–255, alpha to 0–1)
$arr = $rgb->getNormalizedArray(255);
// ['R' => 51, 'G' => 102, 'B' => 153, 'A' => 1]
// Invert without mutating the receiver, then find the closest named web color
$name = $web->getClosestWebColor($rgb->withInvertedColor()->toRgbArray());
// Perceptual match in CIE Lab instead of Euclidean distance in sRGB
echo $web->getClosestWebColorFromString('#9577a6'); // lightslategray
echo $web->getClosestWebColorByDeltaEFromString('#9577a6'); // plum
PDF Colors
<?php
require_once __DIR__ . '/vendor/autoload.php';
$pdf = new \Com\Tecnick\Color\Pdf();
// Emit a PDF fill color operator from any CSS/hex/named color string
echo $pdf->getPdfColor('#ff0000'); // 1.000000 0.000000 0.000000 rg
echo $pdf->getPdfColor('#ff0000', true); // 1.000000 0.000000 0.000000 RG (stroke)
// Emit PDF color components only (for custom operators)
echo $pdf->getPdfRgbComponents('#336699'); // 0.200000 0.400000 0.600000
// JavaScript color string for PDF annotations
echo $pdf->getJsColorString('red'); // color.red
echo $pdf->getJsColorString('#336699'); // ["RGB",0.200000,0.400000,0.600000]
// Get a color model object from any string
$obj = $pdf->getColorObject('cmyk(0,50%,100%,0)');
echo $obj->getPdfColor();
// Force the device color for a name that is also a spot color name
echo $pdf->getPdfFillColor('green', 1, false);
Spot Colors
<?php
require_once __DIR__ . '/vendor/autoload.php';
$pdf = new \Com\Tecnick\Color\Pdf();
// Register a custom spot color (CMYK components 0–1)
$pdf->addSpotColorFromArray('PANTONE 032 C', [
'cyan' => 0,
'magenta' => 0.91,
'yellow' => 0.86,
'key' => 0,
]);
// Or register a Lab-based spot color
$pdf->addSpotLabColor('My Lab Spot', 50.0, 10.0, -20.0);
// Retrieve a copy of the spot color object
$spot = $pdf->getSpotColorObj('PANTONE 032 C');
echo $spot->getPdfColor();
// Generate PDF spot color resource objects for the document header,
// then the resource dictionary that references them
$pon = 10;
echo $pdf->getPdfSpotObjects($pon);
echo $pdf->getPdfSpotResources();
Every registered spot color must be emitted by getPdfSpotObjects() before getPdfSpotResources() is called, otherwise the resource writers raise a \Com\Tecnick\Color\Exception.
Eight of the eleven default spot color names are also CSS color names (red, green, blue, cyan, magenta, yellow, black, white) and resolve to the spot color. They agree with their CSS namesake except green: the spot Green is #00ff00 while CSS green is #008000. Pass $allowSpot = false to force the device color. The remaining three, key, all and none, are spot-only names: with $allowSpot = false they do not resolve, and the color getters return an empty string while getColorObject() returns null.
Behavior Worth Knowing
- Spot colors are registered only when you add them explicitly. The color getters do not register one as a side effect, so the spot resources a document emits match the ones it actually uses.
- Spot color names are escaped when written to PDF, and the CSS parser recognizes the standard spot color names.
- Spot colors take a
DeviceCMYKor a Lab alternate color space in PDF output. - HSL saturation and lightness are always parsed as percentages, as the CSS specification requires.
Integration Notes
Parse color notation once, at the edge of your application, and pass typed model objects inward. Strings that reach the rendering layer get reparsed, sometimes under different assumptions.
RGB and CMYK do not cover the same gamut, so a screen preview and a press sheet will differ for saturated colors no matter how the conversion is done. Decide which one is authoritative for a given document and convert in one direction only.
Lab is the device-independent option, and it is what ISO 19005 prefers. A DeviceCMYK color in a PDF/A document is only valid when the output intent is a CMYK profile, and tc-lib-pdf reports the mismatch through getWarnings(); see /docs/standards/.
Pin your brand colors with golden-file tests. Rounding in a conversion chain drifts quietly, and a logo two units off is not something code review catches.
Requirements
- PHP 8.2 or later
- Extension:
pcre - Composer
Development and Packaging
- QA and local checks:
make deps,make help,make qa - Coverage report:
make qa-coverage - Local example server:
make server - Packaging:
make rpm,make deb
Support and Contribution
- Sponsor: https://github.com/sponsors/tecnickcom
- Contribution guide: https://github.com/tecnickcom/tc-lib-color/blob/main/CONTRIBUTING.md
- Security policy: https://github.com/tecnickcom/tc-lib-color/blob/main/SECURITY.md