Graphics
The graphics namespace covers everything between “set fill colour” and “fill the path” — including the colour spaces, patterns, shadings, and functions that drive rendering.
Shadings
Section titled “Shadings”ShadingType2 (axial) and ShadingType3 (radial) are the workhorses. Both are driven by a Func (usually a FunctionType2) that interpolates between two colour stops.
use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Core\Graphics\ColorSpace\DeviceRGB;use Phpdftk\Pdf\Core\Graphics\Function\FunctionType2;use Phpdftk\Pdf\Core\Graphics\Pattern\ShadingPattern;use Phpdftk\Pdf\Core\Graphics\Shading\ShadingType2;use Phpdftk\Pdf\Core\Graphics\Shading\ShadingType3;use Phpdftk\Pdf\Core\PdfArray;use Phpdftk\Pdf\Core\PdfNumber;use Phpdftk\Pdf\Writer\PdfWriter;
$writer = new PdfWriter();$page = $writer->addPage();$body = $writer->addFont(new Type1Font(StandardFont::Helvetica));$bold = $writer->addFont(new Type1Font(StandardFont::HelveticaBold));
// A Type 2 function defines the color ramp used by every shading on this page:// magenta at t=0, cyan at t=1, linear interpolation in between.$ramp = new FunctionType2( domain: new PdfArray([new PdfNumber(0), new PdfNumber(1)]), c0: new PdfArray([new PdfNumber(0.9), new PdfNumber(0.2), new PdfNumber(0.5)]), c1: new PdfArray([new PdfNumber(0.2), new PdfNumber(0.6), new PdfNumber(0.9)]), n: 1.0,);$rampRef = $writer->register($ramp);
// Axial (linear) shading from x=72 to x=540.$axial = new ShadingType2( new DeviceRGB(), new PdfArray([ new PdfNumber(72), new PdfNumber(0), new PdfNumber(540), new PdfNumber(0), ]), $rampRef,);$axialRef = $writer->register($axial);$axialPattern = $writer->register(new ShadingPattern($axialRef));
// Radial shading centered at (306, 380), starting at radius 0 and ending at radius 180.$radial = new ShadingType3( new DeviceRGB(), new PdfArray([ new PdfNumber(306), new PdfNumber(380), new PdfNumber(0), new PdfNumber(306), new PdfNumber(380), new PdfNumber(180), ]), $rampRef,);$radialRef = $writer->register($radial);$radialPattern = $writer->register(new ShadingPattern($radialRef));
// Expose both patterns under page resources.$page->corePage()->resources->pattern = [ 'P1' => $axialPattern, 'P2' => $radialPattern,];
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($bold, 22)->moveTextPosition(72, 740) ->showText('Shadings')->endText();
$cs->beginText()->setFont($body, 11)->moveTextPosition(72, 690) ->showText('Axial shading — Type 2 function ramped along a linear axis:') ->endText();$cs->raw('/Pattern cs');$cs->raw('/P1 scn');$cs->rectangle(72, 620, 468, 50)->fill();
$cs->beginText()->setFont($body, 11)->moveTextPosition(72, 580) ->showText('Radial shading — same ramp from center outward:') ->endText();$cs->raw('/Pattern cs');$cs->raw('/P2 scn');$cs->rectangle(126, 200, 360, 360)->fill();
$writer->save('shadings.pdf');📄 View the sample PDF · View the full script on GitHub ↗
Tiling patterns
Section titled “Tiling patterns”TilingPattern defines a repeating motif by embedding a small content stream that’s painted across the fill area. Cell size is set by xStep and yStep.
use Phpdftk\Pdf\Core\Content\Resources;use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Core\Graphics\Pattern\TilingPattern;use Phpdftk\Pdf\Core\PdfArray;use Phpdftk\Pdf\Core\PdfNumber;use Phpdftk\Pdf\Writer\PdfWriter;
$writer = new PdfWriter();$page = $writer->addPage();$body = $writer->addFont(new Type1Font(StandardFont::Helvetica));$bold = $writer->addFont(new Type1Font(StandardFont::HelveticaBold));
$bbox = static fn () => new PdfArray([ new PdfNumber(0), new PdfNumber(0), new PdfNumber(20), new PdfNumber(20),]);
// Checkerboard tile: two filled squares in a 20×20 cell.$checker = new TilingPattern( paintType: 1, tilingType: 1, bbox: $bbox(), xStep: 20, yStep: 20, resources: new Resources(), contentStream: "0.92 0.96 1 rg\n0 0 20 20 re\nf\n" . "0.20 0.36 0.85 rg\n0 0 10 10 re\nf\n" . "0.20 0.36 0.85 rg\n10 10 10 10 re\nf\n",);
// Dot grid tile: a single small filled circle (approximated by curves).$dots = new TilingPattern( paintType: 1, tilingType: 1, bbox: $bbox(), xStep: 20, yStep: 20, resources: new Resources(), contentStream: "1 1 1 rg\n0 0 20 20 re\nf\n" . "0.85 0.20 0.36 rg\n" . "10 6 m " . "12.21 6 14 7.79 14 10 c " . "14 12.21 12.21 14 10 14 c " . "7.79 14 6 12.21 6 10 c " . "6 7.79 7.79 6 10 6 c f\n",);
$checkerRef = $writer->register($checker);$dotsRef = $writer->register($dots);
$page->corePage()->resources->pattern = [ 'P1' => $checkerRef, 'P2' => $dotsRef,];
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($bold, 22)->moveTextPosition(72, 740) ->showText('Tiling Patterns')->endText();
$cs->beginText()->setFont($body, 11)->moveTextPosition(72, 700) ->showText('Checkerboard pattern (paintType 1, 20×20 cell):') ->endText();$cs->raw('/Pattern cs');$cs->raw('/P1 scn');$cs->rectangle(72, 480, 468, 200)->fill();
$cs->beginText()->setFont($body, 11)->moveTextPosition(72, 440) ->showText('Dot-grid pattern (curves approximating circles):') ->endText();$cs->raw('/Pattern cs');$cs->raw('/P2 scn');$cs->rectangle(72, 220, 468, 200)->fill();
$writer->save('patterns.pdf');📄 View the sample PDF · View the full script on GitHub ↗
Transparency and blend modes
Section titled “Transparency and blend modes”ExtGState configures the graphics state — including fill/stroke alpha and blend modes. The Multiply blend mode below mixes three primaries the way subtractive inks would.
use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Core\Graphics\ExtGState;use Phpdftk\Pdf\Writer\PdfWriter;
$writer = new PdfWriter();$page = $writer->addPage();$body = $writer->addFont(new Type1Font(StandardFont::Helvetica))->getResourceName();$bold = $writer->addFont(new Type1Font(StandardFont::HelveticaBold))->getResourceName();
// Define a graphics state for each alpha level we want to demonstrate.$alphaStates = ['GS25' => 0.25, 'GS50' => 0.50, 'GS75' => 0.75, 'GS100' => 1.0];foreach ($alphaStates as $name => $alpha) { $gs = new ExtGState(); $gs->caLower = $alpha; // /ca — fill alpha $gs->ca = $alpha; // /CA — stroke alpha $ref = $writer->register($gs); $page->corePage()->resources->addExtGState($name, $ref);}
// Define a Multiply blend mode so overlapping circles mix.$blend = new ExtGState();$blend->bm = new \Phpdftk\Pdf\Core\PdfName('Multiply');$page->corePage()->resources->addExtGState('GSMul', $writer->register($blend));
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($bold, 22)->moveTextPosition(72, 740) ->showText('Transparency & Blend Modes')->endText();
// Row 1 — four squares at increasing alpha over a striped background.$cs->beginText()->setFont($body, 11)->moveTextPosition(72, 700) ->showText('Fill alpha 0.25 / 0.50 / 0.75 / 1.00 over a striped backdrop:') ->endText();
// Vertical stripes backgroundfor ($x = 72; $x < 540; $x += 24) { $cs->setFillColorRGB(0.85, 0.85, 0.92); $cs->rectangle($x, 580, 12, 100)->fill();}
$x = 90;foreach ($alphaStates as $name => $_alpha) { $cs->saveGraphicsState(); $cs->setGraphicsState($name); $cs->setFillColorRGB(0.85, 0.15, 0.35); $cs->rectangle($x, 590, 90, 80)->fill(); $cs->restoreGraphicsState(); $x += 115;}
// Row 2 — three overlapping discs using a Multiply blend mode.$cs->beginText()->setFont($body, 11)->moveTextPosition(72, 550) ->showText('Multiply blend mode mixing three CMYK-like primaries:') ->endText();
$disc = static function ($cs, float $cx, float $cy, float $r): void { // Approximate a circle with cubic Béziers (Kappa ≈ 0.5523). $k = 0.5523 * $r; $cs->moveTo($cx - $r, $cy); $cs->curveTo($cx - $r, $cy + $k, $cx - $k, $cy + $r, $cx, $cy + $r); $cs->curveTo($cx + $k, $cy + $r, $cx + $r, $cy + $k, $cx + $r, $cy); $cs->curveTo($cx + $r, $cy - $k, $cx + $k, $cy - $r, $cx, $cy - $r); $cs->curveTo($cx - $k, $cy - $r, $cx - $r, $cy - $k, $cx - $r, $cy); $cs->closePath(); $cs->fill();};
$cs->saveGraphicsState();$cs->setGraphicsState('GSMul');
$cs->setFillColorRGB(0.95, 0.20, 0.20);$disc($cs, 230, 380, 80);
$cs->setFillColorRGB(0.20, 0.75, 0.30);$disc($cs, 300, 380, 80);
$cs->setFillColorRGB(0.20, 0.30, 0.95);$disc($cs, 265, 320, 80);
$cs->restoreGraphicsState();
$writer->save('transparency.pdf');📄 View the sample PDF · View the full script on GitHub ↗
Color spaces
Section titled “Color spaces”DeviceRGB, DeviceCMYK, and DeviceGray are the three device-dependent spaces. The content stream API exposes setFillColorRGB, setFillColorCMYK, and setFillColorGray directly.
use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Writer\PdfWriter;
$writer = new PdfWriter();$page = $writer->addPage();$body = $writer->addFont(new Type1Font(StandardFont::Helvetica));$bold = $writer->addFont(new Type1Font(StandardFont::HelveticaBold));
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($bold, 22)->moveTextPosition(72, 740) ->showText('Device Color Spaces')->endText();
// ---- DeviceRGB ----------------------------------------------------------$cs->beginText()->setFont($bold, 13)->moveTextPosition(72, 700) ->showText('DeviceRGB (additive — used for screens):')->endText();
$rgb = [ [1.0, 0.0, 0.0, 'Red'], [0.0, 1.0, 0.0, 'Green'], [0.0, 0.0, 1.0, 'Blue'], [1.0, 1.0, 0.0, 'Yellow'], [1.0, 0.0, 1.0, 'Magenta'], [0.0, 1.0, 1.0, 'Cyan'],];$x = 72;foreach ($rgb as [$r, $g, $b, $label]) { $cs->setFillColorRGB($r, $g, $b); $cs->rectangle($x, 620, 70, 50)->fill(); $cs->setFillColorRGB(0, 0, 0); $cs->beginText()->setFont($body, 9)->moveTextPosition($x, 605) ->showText($label)->endText(); $x += 78;}
// ---- DeviceCMYK ---------------------------------------------------------$cs->beginText()->setFont($bold, 13)->moveTextPosition(72, 560) ->showText('DeviceCMYK (subtractive — used for print):')->endText();
$cmyk = [ [0.0, 0.0, 0.0, 0.0, 'White (0,0,0,0)'], [1.0, 0.0, 0.0, 0.0, 'Cyan'], [0.0, 1.0, 0.0, 0.0, 'Magenta'], [0.0, 0.0, 1.0, 0.0, 'Yellow'], [0.0, 0.0, 0.0, 1.0, 'Black'], [0.6, 0.4, 0.0, 0.0, 'Mid blue'],];$x = 72;foreach ($cmyk as [$c, $m, $y, $k, $label]) { $cs->setFillColorCMYK($c, $m, $y, $k); $cs->rectangle($x, 480, 70, 50)->fill(); $cs->setFillColorRGB(0, 0, 0); $cs->beginText()->setFont($body, 9)->moveTextPosition($x, 465) ->showText($label)->endText(); $x += 78;}
// ---- DeviceGray --------------------------------------------------------$cs->beginText()->setFont($bold, 13)->moveTextPosition(72, 420) ->showText('DeviceGray ramp:')->endText();
for ($i = 0; $i <= 10; $i++) { $gray = $i / 10; $cs->setFillColorGray($gray); $cs->rectangle(72 + $i * 42, 340, 40, 60)->fill();}
$writer->save('color-spaces.pdf');📄 View the sample PDF · View the full script on GitHub ↗
Functions
Section titled “Functions”A PDF function maps an input domain to an output range. FunctionType2 (exponential interpolation) and FunctionType3 (stitching) are the most common ways to define colour ramps.
use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Core\Graphics\ColorSpace\DeviceRGB;use Phpdftk\Pdf\Core\Graphics\Function\FunctionType2;use Phpdftk\Pdf\Core\Graphics\Function\FunctionType3;use Phpdftk\Pdf\Core\Graphics\Pattern\ShadingPattern;use Phpdftk\Pdf\Core\Graphics\Shading\ShadingType2;use Phpdftk\Pdf\Core\PdfArray;use Phpdftk\Pdf\Core\PdfNumber;use Phpdftk\Pdf\Writer\PdfWriter;
$writer = new PdfWriter();$page = $writer->addPage();$body = $writer->addFont(new Type1Font(StandardFont::Helvetica))->getResourceName();$bold = $writer->addFont(new Type1Font(StandardFont::HelveticaBold))->getResourceName();
// Helper: build an exponential function ramp between two RGB triplets.$ramp = static function (array $c0, array $c1, float $n = 1.0) { return new FunctionType2( domain: new PdfArray([new PdfNumber(0), new PdfNumber(1)]), c0: new PdfArray(array_map(fn ($v) => new PdfNumber($v), $c0)), c1: new PdfArray(array_map(fn ($v) => new PdfNumber($v), $c1)), n: $n, );};
// 1) Linear Type 2 function: blue → orange.$linear = $writer->register($ramp([0.10, 0.30, 0.85], [0.95, 0.55, 0.10], 1.0));
// 2) Non-linear Type 2 function with N=4 (a steep falloff).$steep = $writer->register($ramp([0.05, 0.05, 0.05], [1.00, 0.85, 0.15], 4.0));
// 3) Stitching (Type 3) function: red → white → green, joined at t=0.5.$redWhite = $ramp([0.85, 0.20, 0.20], [1.0, 1.0, 1.0]);$whiteGreen = $ramp([1.0, 1.0, 1.0], [0.10, 0.55, 0.20]);$redWhiteRef = $writer->register($redWhite);$whiteGreenRef = $writer->register($whiteGreen);
$stitching = new FunctionType3( domain: new PdfArray([new PdfNumber(0), new PdfNumber(1)]), functions: new PdfArray([$redWhiteRef, $whiteGreenRef]), bounds: new PdfArray([new PdfNumber(0.5)]), encode: new PdfArray([ new PdfNumber(0), new PdfNumber(1), new PdfNumber(0), new PdfNumber(1), ]),);$stitchingRef = $writer->register($stitching);
// Wire each function to an axial shading and a pattern for paint.$axisCoords = new PdfArray([ new PdfNumber(72), new PdfNumber(0), new PdfNumber(540), new PdfNumber(0),]);$bands = [ ['P1', $linear, 640, 'Type 2 — linear (N=1):'], ['P2', $steep, 540, 'Type 2 — exponential (N=4):'], ['P3', $stitchingRef, 440, 'Type 3 — stitching of two ramps:'],];
foreach ($bands as [$name, $funcRef, $y, $label]) { $shading = new ShadingType2(new DeviceRGB(), $axisCoords, $funcRef); $shadingRef = $writer->register($shading); $page->corePage()->resources->pattern[$name] = $writer->register(new ShadingPattern($shadingRef));}
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($bold, 22)->moveTextPosition(72, 740) ->showText('Functions')->endText();$cs->beginText()->setFont($body, 11)->moveTextPosition(72, 706) ->showText('Functions drive the color computation behind every shading.') ->endText();
foreach ($bands as [$name, , $y, $label]) { $cs->beginText()->setFont($body, 11)->moveTextPosition(72, $y + 50) ->showText($label)->endText(); $cs->raw('/Pattern cs'); $cs->raw('/' . $name . ' scn'); $cs->rectangle(72, $y, 468, 40)->fill();}
$writer->save('functions.pdf');