Skip to content

Commit 5e04fe6

Browse files
committed
refactor: isolate gradient soft-mask state, fix docs and redundancies
Internal cleanup and documentation accuracy pass over the graph library. No change to rendered PDF output except the removal of redundant operators. - Gradient: move transparency soft-mask pattern bookkeeping out of $gradients into a dedicated, fully-typed $gradientMasks property so getGradientsArray() always returns complete GradientData entries. Removes the obsolete @PHPStan-Ignore comments (project uses mago). - Gradient: stop advertising the internal DeviceGray soft-mask shading/pattern in the page-level gradient resource dictionary; it is only referenced from within the soft-mask form XObject. - Draw::getArrow(): do not re-emit the line style for the arrowhead, as it already persists in the graphics state (updates testGetArrow). - Raw::getRawEllipticalArc(): compute the optional $bbox in float instead of truncating coordinates to int. - Gradient: normalize default CMYK registration-bar colors to consistent percent form (parse-identical, no output change). - Docs: fix getPathPaintOp() CNZ/CEO clipping-rule descriptions and the b* operator, add getAlpha() $ais param, and correct the setRawEllipticalArcAngles() parameter order.
1 parent 49bcd2a commit 5e04fe6

11 files changed

Lines changed: 70 additions & 63 deletions

File tree

.gitignore

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
**/*.bak
2-
**/*.tmp
1+
.phpdoc
2+
.phpunit.cache
3+
.phpunit.result.cache
4+
**/._*
35
**/.#*
46
**/.DS_Store
5-
**/._*
67
**/.idea
78
**/.vagrant
9+
**/*.bak
10+
**/*.tmp
811
**/auth.json
912
**/nbproject
1013
**/temp.php
1114
**/test.php
12-
.phpdoc
13-
.phpunit.cache
14-
.phpunit.result.cache
1515
composer.lock
1616
ecs.php
1717
phpunit.xml
18+
PLAN_*
1819
rector.php
1920
target
2021
vendor

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.13.0
1+
2.14.0

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
"require": {
2828
"php": ">=8.2",
2929
"ext-zlib": "*",
30-
"tecnickcom/tc-lib-color": "^2.11",
31-
"tecnickcom/tc-lib-pdf-encrypt": "^2.7"
30+
"tecnickcom/tc-lib-color": "^2.12",
31+
"tecnickcom/tc-lib-pdf-encrypt": "^2.8"
3232
},
3333
"minimum-stability": "stable",
3434
"prefer-stable": true,

resources/debian/control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ Vcs-Browser: https://github.com/~#VENDOR#~/~#PROJECT#~
1212
Package: ~#PKGNAME#~
1313
Provides: php-~#PROJECT#~
1414
Architecture: all
15-
Depends: php (>= 8.2.0), php-zip, php-tecnickcom-tc-lib-color (<< 3.0.0), php-tecnickcom-tc-lib-color (>= 2.11.0), php-tecnickcom-tc-lib-pdf-encrypt (<< 3.0.0), php-tecnickcom-tc-lib-pdf-encrypt (>= 2.7.0), ${misc:Depends}
15+
Depends: php (>= 8.2.0), php-zip, php-tecnickcom-tc-lib-color (<< 3.0.0), php-tecnickcom-tc-lib-color (>= 2.12.1), php-tecnickcom-tc-lib-pdf-encrypt (<< 3.0.0), php-tecnickcom-tc-lib-pdf-encrypt (>= 2.8.0), ${misc:Depends}
1616
Description: PHP PDF Graph Library
1717
PHP library containing PDF graphic and geometric methods.

resources/rpm/rpm.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ BuildArch: noarch
1717
Requires: php(language) >= 8.2.0
1818
Requires: php-zlib
1919
Requires: php-composer(%{c_vendor}/tc-lib-color) < 3.0.0
20-
Requires: php-composer(%{c_vendor}/tc-lib-color) >= 2.11.0
20+
Requires: php-composer(%{c_vendor}/tc-lib-color) >= 2.12.1
2121
Requires: php-composer(%{c_vendor}/tc-lib-pdf-encrypt) < 3.0.0
22-
Requires: php-composer(%{c_vendor}/tc-lib-pdf-encrypt) >= 2.7.0
22+
Requires: php-composer(%{c_vendor}/tc-lib-pdf-encrypt) >= 2.8.0
2323

2424
Provides: php-composer(%{c_vendor}/%{gh_project}) = %{version}
2525
Provides: php-%{gh_project} = %{version}

src/Base.php

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,19 @@ abstract class Base
164164
*/
165165
protected array $gradients = [];
166166

167+
/**
168+
* Bookkeeping for the luminosity soft-mask patterns generated for
169+
* transparent gradients, keyed by the transparency pattern index used as
170+
* the resource name (/p{key}) inside the soft-mask form XObject.
171+
*
172+
* These are internal helper objects, referenced only from within the
173+
* soft-mask XObject, and are deliberately kept out of $gradients so they
174+
* are not advertised in the page-level gradient resource dictionary.
175+
*
176+
* @var array<int, array{'id': int, 'pattern': int}>
177+
*/
178+
protected array $gradientMasks = [];
179+
167180
/**
168181
* Initialize
169182
*
@@ -632,7 +645,7 @@ protected function getOutPatternObj(array $grad, int $objref): string
632645

633646
$oid = ++$this->pon;
634647
$coords = $grad['coords'];
635-
$out = $oid . ' 0 obj' . "\n" . '<<' . ' /ShadingType ' . $grad['type'] . ' /ColorSpace /' . $grad['colspace'];
648+
$out = $oid . ' 0 obj' . "\n" . '<< /ShadingType ' . $grad['type'] . ' /ColorSpace /' . $grad['colspace'];
636649
if ($grad['background'] !== null) {
637650
$out .= ' /Background [' . $grad['background']->getComponentsString() . ']';
638651
}
@@ -722,7 +735,6 @@ public function getOutGradientShaders(int $pon): string
722735
if ($gcol !== '') {
723736
$out .= $gcol;
724737
$this->gradients[$idx]['id'] = $this->pon - 1;
725-
// @phpstan-ignore assign.propertyType
726738
$this->gradients[$idx]['pattern'] = $this->pon;
727739
}
728740

@@ -731,14 +743,15 @@ public function getOutGradientShaders(int $pon): string
731743

732744
if ($gopa !== '') {
733745
$out .= $gopa;
734-
// @phpstan-ignore assign.propertyType
735-
$this->gradients[$idgs]['id'] = $this->pon - 1;
736-
// @phpstan-ignore assign.propertyType
737-
$this->gradients[$idgs]['pattern'] = $this->pon;
746+
$this->gradientMasks[$idgs] = [
747+
'id' => $this->pon - 1,
748+
'pattern' => $this->pon,
749+
];
738750
}
739751

740752
if ($grad['transparency']) {
741-
if (!isset($this->gradients[$idgs]['pattern'])) {
753+
$mask = $this->gradientMasks[$idgs] ?? null;
754+
if ($mask === null) {
742755
// no transparency pattern was generated: skip without emitting a partial object
743756
continue;
744757
}
@@ -748,7 +761,7 @@ public function getOutGradientShaders(int $pon): string
748761
$pheight = $this->pageh * $this->kunit;
749762
$rect = \sprintf('%F %F', $pwidth, $pheight);
750763

751-
$out .= $oid . ' 0 obj' . "\n" . '<<' . ' /Type /XObject' . ' /Subtype /Form' . ' /FormType 1';
764+
$out .= $oid . ' 0 obj' . "\n" . '<< /Type /XObject /Subtype /Form /FormType 1';
752765
$stream = 'q /a0 gs /Pattern cs /p' . $idgs . ' scn 0 0 ' . $pwidth . ' ' . $pheight . ' re f Q';
753766
if ($this->compress) {
754767
$cmpstream = \gzcompress($stream);
@@ -771,7 +784,7 @@ public function getOutGradientShaders(int $pon): string
771784
. ' /Pattern << /p'
772785
. $idgs
773786
. ' '
774-
. $this->gradients[$idgs]['pattern']
787+
. $mask['pattern']
775788
. ' 0 R >>'
776789
. ' >>'
777790
. ' >>'

src/Draw.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,9 @@ public function getArrow(
691691
3 => 'f',
692692
];
693693
$points = [$hxl, $hyl, $posx1, $posy1, $hxr, $hyr];
694-
return $out . $this->getBasicPolygon($points, $modemap[$headmode] ?? 'S', $style);
694+
// The style was already emitted above and persists in the graphics
695+
// state, so the arrowhead does not need to repeat it.
696+
return $out . $this->getBasicPolygon($points, $modemap[$headmode] ?? 'S');
695697
}
696698

697699
/**

src/Gradient.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -722,21 +722,21 @@ public function getColorRegistrationBar(
722722
bool $vertical = false,
723723
array $colors = [
724724
// GRAY : black to white
725-
['g(0%)', 'g(100%)'],
725+
['g(0%)', 'g(100%)'],
726726
// RGB : red to white
727-
['rgb(100%,0%,0%)', 'rgb(100%,100%,100%)'],
727+
['rgb(100%,0%,0%)', 'rgb(100%,100%,100%)'],
728728
// RGB : green to white
729-
['rgb(0%,100%,0%)', 'rgb(100%,100%,100%)'],
729+
['rgb(0%,100%,0%)', 'rgb(100%,100%,100%)'],
730730
// RGB : blue to white
731-
['rgb(0%,0%,100%)', 'rgb(100%,100%,100%)'],
731+
['rgb(0%,0%,100%)', 'rgb(100%,100%,100%)'],
732732
// CMYK : cyan to white
733-
['cmyk(100%,0%,0,0%)', 'cmyk(0%,0%,0,0%)'],
733+
['cmyk(100%,0%,0%,0%)', 'cmyk(0%,0%,0%,0%)'],
734734
// CMYK : magenta to white
735-
['cmyk(0%,100%,0,0%)', 'cmyk(0%,0%,0,0%)'],
735+
['cmyk(0%,100%,0%,0%)', 'cmyk(0%,0%,0%,0%)'],
736736
// CMYK : yellow to white
737-
['cmyk(0%,0%,100,0%)', 'cmyk(0%,0%,0,0%)'],
737+
['cmyk(0%,0%,100%,0%)', 'cmyk(0%,0%,0%,0%)'],
738738
// CMYK : black to white
739-
['cmyk(0%,0%,0,100%)', 'cmyk(0%,0%,0,0%)'],
739+
['cmyk(0%,0%,0%,100%)', 'cmyk(0%,0%,0%,0%)'],
740740
],
741741
): string {
742742
$numbars = \count($colors);
@@ -928,6 +928,9 @@ public function getOverprint(bool $stroking = true, ?bool $nonstroking = null, i
928928
* @param float|string $nonstroking Alpha value for non-stroking operations:
929929
* real value from 0 (transparent) to 1
930930
* (opaque).
931+
* @param bool $ais Alpha-Is-Shape flag: if true the soft-mask
932+
* alpha values are interpreted as shape
933+
* (passed through to the /AIS ExtGState key).
931934
*
932935
* @return string PDF command
933936
*/

src/Raw.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ public function getRawCurveY(float $posx1, float $posy1, float $posx3, float $po
169169
*
170170
* @param float $ags Angle in degrees at which starting drawing.
171171
* @param float $agf Angle in degrees at which stop drawing.
172-
* @param float $rdh Horizontal radius.
173172
* @param float $rdv Vertical radius (if = 0 then it is a circle).
173+
* @param float $rdh Horizontal radius.
174174
* @param bool $ccw If true draws in counter-clockwise direction.
175175
* @param bool $svg If true the angles are in svg mode (already calculated).
176176
*/
@@ -222,8 +222,10 @@ protected function setRawEllipticalArcAngles(
222222
* @param bool $startpoint If true output a starting point.
223223
* @param bool $ccw If true draws in counter-clockwise direction.
224224
* @param bool $svg If true the angles are in svg mode (already calculated).
225-
* @param array<int> $bbox If provided, it will be filled with the bounding box coordinates
226-
* (x min, y min, x max, y max).
225+
* @param array<float> $bbox If provided, it will be filled with the bounding box coordinates
226+
* (x min, y min, x max, y max). The box is derived from the Bezier
227+
* control points, so (by the convex-hull property) it is guaranteed
228+
* to contain the arc but may be slightly larger than its tight bounds.
227229
*
228230
* @return string PDF command
229231
*
@@ -322,10 +324,10 @@ public function getRawEllipticalArc(
322324
$out .= $this->getRawCurve($cx1, $cy1, $cx2, $cy2, $cx3, $cy3);
323325
// get bounding box coordinates
324326
$bbox = [
325-
\min($bbox[0], (int) $cx1, (int) $cx2, (int) $cx3),
326-
\min($bbox[1], (int) $cy1, (int) $cy2, (int) $cy3),
327-
\max($bbox[2], (int) $cx1, (int) $cx2, (int) $cx3),
328-
\max($bbox[3], (int) $cy1, (int) $cy2, (int) $cy3),
327+
\min($bbox[0], $cx1, $cx2, $cx3),
328+
\min($bbox[1], $cy1, $cy2, $cy3),
329+
\max($bbox[2], $cx1, $cx2, $cx3),
330+
\max($bbox[3], $cy1, $cy2, $cy3),
329331
];
330332
// move to next point
331333
$px1 = $px2;
@@ -338,10 +340,10 @@ public function getRawEllipticalArc(
338340
$out .= $this->getRawLine($posxc, $posyc);
339341
// get bounding box coordinates
340342
$bbox = [
341-
\min($bbox[0], (int) $posxc),
342-
\min($bbox[1], (int) $posyc),
343-
\max($bbox[2], (int) $posxc),
344-
\max($bbox[3], (int) $posyc),
343+
\min($bbox[0], $posxc),
344+
\min($bbox[1], $posyc),
345+
\max($bbox[2], $posxc),
346+
\max($bbox[3], $posyc),
345347
];
346348
}
347349

src/Style.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ public function getCurrentStyleItem(string $item): mixed
314314
throw new GraphException('The ' . $item . ' value is not set in the current style');
315315
}
316316

317-
return $style[$item] ?? null;
317+
return $style[$item];
318318
}
319319

320320
/**
@@ -415,15 +415,15 @@ protected function getLineModeCmd(array $style = []): string
415415
* or df: Close, fill, and then stroke the
416416
* path, using the nonzero winding number
417417
* rule to determine the region to fill. -
418-
* b or f*d or df*: Close, fill, and then
418+
* b* or f*d or df*: Close, fill, and then
419419
* stroke the path, using the even-odd
420420
* rule to determine the region to fill. -
421-
* CNZ: Clipping mode using the even-odd
421+
* CNZ: Clipping mode using the nonzero
422+
* winding number rule to determine which
423+
* regions lie inside the clipping path. -
424+
* CEO: Clipping mode using the even-odd
422425
* rule to determine which regions lie
423-
* inside the clipping path. - CEO:
424-
* Clipping mode using the nonzero winding
425-
* number rule to determine which regions
426-
* lie inside the clipping path - n: End
426+
* inside the clipping path - n: End
427427
* the path object without filling or
428428
* stroking it.
429429
* @param string $default Default style

0 commit comments

Comments
 (0)