Feature: Labelprint für Kistenetiketten hinzugefügt

This commit is contained in:
2025-10-27 12:14:44 +01:00
parent 43bc416554
commit 14bae6c9ef
1068 changed files with 229014 additions and 1807 deletions

View File

@@ -0,0 +1,789 @@
<?php
/**
* Base.php
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
use Com\Tecnick\Pdf\Exception as PdfException;
use Com\Tecnick\Barcode\Barcode as ObjBarcode;
use Com\Tecnick\Color\Pdf as ObjColor;
use Com\Tecnick\File\Cache as ObjCache;
use Com\Tecnick\File\File as ObjFile;
use Com\Tecnick\Pdf\Encrypt\Encrypt as ObjEncrypt;
use Com\Tecnick\Pdf\Font\Stack as ObjFont;
use Com\Tecnick\Pdf\Graph\Draw as ObjGraph;
use Com\Tecnick\Pdf\Image\Import as ObjImage;
use Com\Tecnick\Pdf\Page\Page as ObjPage;
use Com\Tecnick\Unicode\Convert as ObjUniConvert;
/**
* Com\Tecnick\Pdf\Base
*
* Output PDF data
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* @phpstan-import-type PageInputData from \Com\Tecnick\Pdf\Page\Box
* @phpstan-import-type PageData from \Com\Tecnick\Pdf\Page\Box
* @phpstan-import-type TFontMetric from \Com\Tecnick\Pdf\Font\Stack
*
* @phpstan-type TViewerPref array{
* 'HideToolbar'?: bool,
* 'HideMenubar'?: bool,
* 'HideWindowUI'?: bool,
* 'FitWindow'?: bool,
* 'CenterWindow'?: bool,
* 'DisplayDocTitle'?: bool,
* 'NonFullScreenPageMode'?: string,
* 'Direction'?: string,
* 'ViewArea'?: string,
* 'ViewClip'?: string,
* 'PrintArea'?: string,
* 'PrintClip'?: string,
* 'PrintScaling'?: string,
* 'Duplex'?: string,
* 'PickTrayByPDFSize'?: bool,
* 'PrintPageRange'?: array<int>,
* 'NumCopies'?: int,
* }
*
* @phpstan-type TBBox array{
* 'x': float,
* 'y': float,
* 'w': float,
* 'h': float,
* }
*
* @phpstan-type TCellDef array{
* 'margin': array{
* 'T': float,
* 'R': float,
* 'B': float,
* 'L': float,
* },
* 'padding': array{
* 'T': float,
* 'R': float,
* 'B': float,
* 'L': float,
* },
* 'borderpos': float,
* }
*
* @phpstan-type TRefUnitValues array{
* 'parent': float,
* 'font': array{
* 'rootsize': float,
* 'size': float,
* 'xheight': float,
* 'zerowidth': float,
* },
* 'viewport': array{
* 'width': float,
* 'height': float,
* },
* 'page': array{
* 'width': float,
* 'height': float,
* },
* }
*
* @phpstan-type TCustomXMP array{
* 'x:xmpmeta': string,
* 'x:xmpmeta.rdf:RDF': string,
* 'x:xmpmeta.rdf:RDF.rdf:Description': string,
* 'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas': string,
* 'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas.rdf:Bag': string,
* }
*
* @phpstan-type TStackBBox array<int, TBBox>
*
* @phpstan-import-type TAnnot from Output
* @phpstan-import-type TEmbeddedFile from Output
* @phpstan-import-type TObjID from Output
* @phpstan-import-type TOutline from Output
* @phpstan-import-type TSignature from Output
* @phpstan-import-type TSignTimeStamp from Output
* @phpstan-import-type TGTransparency from Output
* @phpstan-import-type TUserRights from Output
* @phpstan-import-type TXOBject from Output
*
* @SuppressWarnings("PHPMD")
*/
abstract class Base
{
/**
* Encrypt object.
*/
public ObjEncrypt $encrypt;
/**
* Color object.
*/
public ObjColor $color;
/**
* Barcode object.
*/
public ObjBarcode $barcode;
/**
* File object.
*/
public ObjFile $file;
/**
* Cache object.
*/
public ObjCache $cache;
/**
* Unicode Convert object.
*/
public ObjUniConvert $uniconv;
/**
* Page object.
*/
public ObjPage $page;
/**
* Graph object.
*/
public ObjGraph $graph;
/**
* Font object.
*/
public ObjFont $font;
/**
* Image Import object.
*/
public ObjImage $image;
/**
* TCPDF version.
*/
protected string $version = '8.1.5';
/**
* Time is seconds since EPOCH when the document was created.
*/
protected int $doctime = 0;
/**
* Time is seconds since EPOCH when the document was modified.
*/
protected int $docmodtime = 0;
/**
* The name of the application that generates the PDF.
*
* If the document was converted to PDF from another format,
* the name of the conforming product that created the original document from which it was converted.
*/
protected string $creator = 'TCPDF';
/**
* The name of the person who created the document.
*/
protected string $author = 'TCPDF';
/**
* Subject of the document.
*/
protected string $subject = '-';
/**
* Title of the document.
*/
protected string $title = 'PDF Document';
/**
* Space-separated list of keywords associated with the document.
*/
protected string $keywords = 'TCPDF';
/**
* Additional custom XMP data.
*
* @var TCustomXMP
*/
protected array $custom_xmp = [
'x:xmpmeta' => '',
'x:xmpmeta.rdf:RDF' => '',
'x:xmpmeta.rdf:RDF.rdf:Description' => '',
'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas' => '',
'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas.rdf:Bag' => '',
];
/**
* Set this to TRUE to add the default sRGB ICC color profile
*/
protected bool $sRGB = false;
/**
* Viewer preferences dictionary controlling the way the document is to be presented on the screen or in print.
* (PDF reference, "Viewer Preferences").
*
* @var TViewerPref
*/
protected array $viewerpref = [];
/**
* Boolean flag to set the default document language direction.
* False = LTR = Left-To-Right.
* True = RTL = Right-To-Left.
*
* @val bool
*/
protected bool $rtl = false;
/**
* Document ID.
*/
protected string $fileid;
/**
* Unit of measure.
*/
protected string $unit = 'mm';
/**
* Valid HTML/CSS/SVG units.
*
* @var array<string>
*/
protected const VALIDUNITS = [
'%', 'ch', 'cm', 'em', 'ex',
'in', 'mm', 'pc', 'pt', 'px',
'rem', 'vh', 'vmax', 'vmin', 'vw',
];
/**
* Map of relative font sizes.
* The key is the relative size and the value is the font size increment in points.
*
* @var array<string, float>
*/
protected const FONTRELSIZE = [
'xx-small' => -4.0,
'x-small' => -3.0,
'smaller' => -3.0,
'small' => -2.0,
'medium' => 0.0,
'large' => 2.0,
'x-large' => 4.0,
'larger' => 3.0,
'xx-large' => 6.0,
];
/**
* Default eference values for unit conversion.
*
* @var TRefUnitValues
*/
protected const REFUNITVAL = [
'parent' => 1.0,
'font' => [
'rootsize' => 10.0,
'size' => 10.0,
'xheight' => 5.0,
'zerowidth' => 3.0,
],
'viewport' => [
'width' => 1000.0,
'height' => 1000.0,
],
'page' => [
'width' => 595.276,
'height' => 841.890,
],
];
/**
* DPI (Dot Per Inch) Document Resolution (do not change).
* 1pt = 1/72 of 1in.
*/
protected float $dpi = 72.0;
/**
* Unit of measure conversion ratio.
*/
protected float $kunit = 1.0;
/**
* Ratio between an internal point and pixel size.
*/
protected float $pointtopixelratio = 1.0;
/**
* Version of the PDF/A mode or 0 otherwise.
*/
protected int $pdfa = 0;
/**
* Enable stream compression.
*/
protected bool $compress = true;
/**
* True if we are in PDF/X mode.
*/
protected bool $pdfx = false;
/**
* True if the document is signed.
*/
protected bool $sign = false;
/**
* True if the signature approval is enabled (for incremental updates).
*/
protected bool $sigapp = false;
/**
* True to subset the fonts.
*/
protected bool $subsetfont = false;
/**
* True for Unicode font mode.
*/
protected bool $isunicode = true;
/**
* Document encoding.
*/
protected string $encoding = 'UTF-8';
/**
* Current PDF object number.
*/
public int $pon = 0;
/**
* PDF version.
*/
protected string $pdfver = '1.7';
/**
* Defines the way the document is to be displayed by the viewer.
*
* @var array{
* zoom: int|string,
* layout: string,
* mode: string,
* }
*/
protected array $display = [
'zoom' => 'default',
'layout' => 'SinglePage',
'mode' => 'UseNone',
];
/**
* Embedded files data.
*
* @var array<string, TEmbeddedFile>
*/
protected array $embeddedfiles = [];
/**
* Annotations indexed bu object IDs.
*
* @var array<int, TAnnot>
*/
protected array $annotation = [];
/**
* Array containing the regular expression used to identify withespaces or word separators.
*
* @var array{
* r: string,
* p: string,
* m: string,
* }
*/
protected array $spaceregexp = [
'r' => '/[^\S\xa0]/',
'p' => '[^\S\xa0]',
'm' => '',
];
/**
* File name of the PDF document.
*/
protected string $pdffilename;
/**
* Raw encoded fFile name of the PDF document.
*/
protected string $encpdffilename;
/**
* Array containing the ID of some named PDF objects.
*
* @var TObjID
*/
protected array $objid = [
'catalog' => 0,
'dests' => 0,
'form' => [],
'info' => 0,
'pages' => 0,
'resdic' => 0,
'signature' => 0,
'srgbicc' => 0,
'xmp' => 0,
];
/**
* Current XOBject template ID.
*
* @var string
*/
protected string $xobjtid = '';
/**
* Outlines Data.
*
* @var array<int, TOutline>
*/
protected array $outlines = [];
/**
* Outlines Root object ID.
*/
protected int $outlinerootoid = 0;
/**
* Javascript catalog entry.
*/
protected string $jstree = '';
/**
* Signature Data.
*
* @var TSignature
*/
protected array $signature = [
'appearance' => [
'empty' => [],
'name' => '',
'page' => 0,
'rect' => '',
],
'approval' => '',
'cert_type' => -1,
'extracerts' => null,
'info' => [
'ContactInfo' => '',
'Location' => '',
'Name' => '',
'Reason' => '',
],
'password' => '',
'privkey' => '',
'signcert' => '',
];
/**
* Signature Timestamp Data.
*
* @var TSignTimeStamp
*/
protected array $sigtimestamp = [
'enabled' => false,
'host' => '',
'username' => '',
'password' => '',
'cert' => '',
];
/**
* ByteRange placemark used during digital signature process.
*
* @var string
*/
protected const BYTERANGE = '/ByteRange[0 ********** ********** **********]';
/**
* Digital signature max length.
*
* @var int
*/
protected const SIGMAXLEN = 11742;
/**
* User rights Data.
*
* @var TUserRights
*/
protected array $userrights = [
'annots' => '/Create/Delete/Modify/Copy/Import/Export',
'document' => '/FullSave',
'ef' => '/Create/Delete/Modify/Import',
'enabled' => false,
'form' => '/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate',
'formex' => '', // 'BarcodePlaintext',
'signature' => '/Modify',
];
/**
* XObjects data.
*
* @var array<string, TXOBject>
*/
protected array $xobjects = [];
/**
* Stack of bounding boxes [x, y, width, height] in user units.
*
* @var TStackBBox
*/
protected array $bbox = [[
'x' => 0,
'y' => 0,
'w' => 0,
'h' => 0,
]];
/**
* Set to true to enable the default page footer.
*
* @var bool
*/
protected bool $defPageContentEnabled = false;
/**
* Default font for defautl page content.
*
* @var ?TFontMetric
*/
protected ?array $defaultfont = null;
/**
* The default relative position of the cell origin when
* the border is centered on the cell edge.
*/
public const BORDERPOS_DEFAULT = 0;
/**
* The relative position of the cell origin when
* the border is external to the cell edge.
*/
public const BORDERPOS_EXTERNAL = -0.5; //-1/2
/**
* The relative position of the cell origin when
* the border is internal to the cell edge.
*/
public const BORDERPOS_INTERNAL = 0.5; // 1/2
/**
* Default values for cell.
*
* @const TCellDef
*/
public const ZEROCELL = [
'margin' => [
'T' => 0,
'R' => 0,
'B' => 0,
'L' => 0,
],
'padding' => [
'T' => 0,
'R' => 0,
'B' => 0,
'L' => 0,
],
'borderpos' => self::BORDERPOS_DEFAULT,
];
/**
* Default values for cell.
*
* @var TCellDef
*/
protected $defcell = self::ZEROCELL;
/**
* Convert user units to internal points unit.
*
* @param float $usr Value to convert.
*/
public function toPoints(float $usr): float
{
return ($usr * $this->kunit);
}
/**
* Convert internal points to user unit.
*
* @param float $pnt Value to convert in user units.
*/
public function toUnit(float $pnt): float
{
return ($pnt / $this->kunit);
}
/**
* Convert vertical user value to internal points unit.
* Note: the internal Y points coordinate starts at the bottom left of the page.
*
* @param float $usr Value to convert.
* @param float $pageh Optional page height in internal points ($pageh:$this->page->getPage()['pheight']).
*/
public function toYPoints(float $usr, float $pageh = -1): float
{
$pageh = $pageh >= 0 ? $pageh : $this->page->getPage()['pheight'];
return ($pageh - $this->toPoints($usr));
}
/**
* Convert vertical internal points value to user unit.
* Note: the internal Y points coordinate starts at the bottom left of the page.
*
* @param float $pnt Value to convert.
* @param float $pageh Optional page height in internal points ($pageh:$this->page->getPage()['pheight']).
*/
public function toYUnit(float $pnt, float $pageh = -1): float
{
$pageh = $pageh >= 0 ? $pageh : $this->page->getPage()['pheight'];
return $this->toUnit($pageh - $pnt);
}
/**
* Enable or disable the default page content.
*
* @param bool $enable Enable or disable the default page content.
*
* @return void
*/
public function enableDefaultPageContent(bool $enable = true): void
{
$this->defPageContentEnabled = $enable;
}
/**
* Set the pixel/point ratio used to convert pixel values to points.
*
* @param float $val
*
* @return void
*/
public function setPointToPixelRatio(float $val): void
{
$this->pointtopixelratio = $val;
}
/**
* Converts a string containing value and unit of measure to internal points.
* This is used to convert values for SVG, CSS, HTML.
*
* @param string|float|int $val String containing values and unit.
* @param TRefUnitValues $ref Reference values in internal points.
* @param string $defunit Default unit (can be one of the VALIDUNITS).
*
* @return float Internal points value.
*/
protected function getUnitValuePoints(
string|float|int $val,
array $ref = self::REFUNITVAL,
string $defunit = 'px',
): float {
$unit = 'px';
if (in_array($defunit, self::VALIDUNITS)) {
$unit = $defunit;
}
$value = 0.0;
if (is_numeric($val)) {
$value = floatval($val);
} elseif (preg_match('/([0-9\.\-\+]+)([a-z%]{0,4})/', $val, $match)) {
$value = floatval($match[1]);
if (in_array($match[2], self::VALIDUNITS)) {
$unit = $match[2];
}
} else {
throw new PdfException('Invalid value: ' . $val);
}
return match ($unit) {
// Percentage relative to the parent element.
'%' => (($value * $ref['parent']) / 100),
// Relative to the width of the "0" (zero)
'ch' => ($value * $ref['font']['zerowidth']),
// Centimeters.
'cm' => (($value * $this->dpi) / 2.54),
// Relative to the font-size of the element.
'em' => ($value * $ref['font']['size']),
// Relative to the x-height of the current font.
'ex' => ($value * $ref['font']['xheight']),
// Inches.
'in' => ($value * $this->dpi),
// Millimeters.
'mm' => (($value * $this->dpi) / 25.4),
// One pica is 12 points.
'pc' => ($value * 12),
// Points.
'pt' => $value,
// Pixels.
'px' => ($value * $this->pointtopixelratio),
// Relative to font-size of the root element.
'rem' => ($value * $ref['font']['rootsize']),
// Relative to 1% of the height of the viewport.
'vh' => (($value * $ref['viewport']['height']) / 100),
// Relative to 1% of viewport's* larger dimension.
'vmax' => (($value * max($ref['viewport']['height'], $ref['viewport']['width'])) / 100),
// Relative to 1% of viewport's smaller dimension.
'vmin' => (($value * min($ref['viewport']['height'], $ref['viewport']['width'])) / 100),
// Relative to 1% of the width of the viewport.
'vw' => (($value * $ref['viewport']['width']) / 100),
// Default to pixels.
default => ($value * $this->pointtopixelratio),
};
}
/**
* Converts a string containing font size value to internal points.
* This is used to convert values for SVG, CSS, HTML.
*
* @param string|float|int $val String containing values and unit.
* @param TRefUnitValues $ref Reference values in internal points.
* @param string $defunit Default unit (can be one of the VALIDUNITS).
*
* @return float Internal points value.
*/
protected function getFontValuePoints(
string|float|int $val,
array $ref = self::REFUNITVAL,
string $defunit = 'pt',
): float {
if (is_string($val) && isset(self::FONTRELSIZE[$val])) {
return ($ref['parent'] + self::FONTRELSIZE[$val]);
}
return $this->getUnitValuePoints($val, $ref, $defunit);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* CSS.php
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
use Com\Tecnick\Pdf\Exception as PdfException;
/**
* Com\Tecnick\Pdf\CSS
*
* CSS PDF class
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*/
abstract class CSS extends \Com\Tecnick\Pdf\SVG
{
}

View File

@@ -0,0 +1,625 @@
<?php
/**
* Text.php
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
/**
* Com\Tecnick\Pdf\Cell
*
* Cell PDF data
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* @phpstan-import-type StyleDataOpt from \Com\Tecnick\Pdf\Graph\Style
* @phpstan-import-type TCellDef from \Com\Tecnick\Pdf\Base
*
*/
abstract class Cell extends \Com\Tecnick\Pdf\Base
{
/**
* Set the default cell margin in user units.
*
* @param float $top Top.
* @param float $right Right.
* @param float $bottom Bottom.
* @param float $left Left.
*/
public function setDefaultCellMargin(
float $top,
float $right,
float $bottom,
float $left
): void {
$this->defcell['margin']['T'] = $this->toPoints($top);
$this->defcell['margin']['R'] = $this->toPoints($right);
$this->defcell['margin']['B'] = $this->toPoints($bottom);
$this->defcell['margin']['L'] = $this->toPoints($left);
}
/**
* Set the default cell padding in user units.
*
* @param float $top Top.
* @param float $right Right.
* @param float $bottom Bottom.
* @param float $left Left.
*/
public function setDefaultCellPadding(
float $top,
float $right,
float $bottom,
float $left
): void {
$this->defcell['padding']['T'] = $this->toPoints($top);
$this->defcell['padding']['R'] = $this->toPoints($right);
$this->defcell['padding']['B'] = $this->toPoints($bottom);
$this->defcell['padding']['L'] = $this->toPoints($left);
}
/**
* Sets the default cell border position.
*
* @param float $borderpos The border position to set:
* BORDERPOS_DEFAULT
* BORDERPOS_EXTERNAL
* BORDERPOS_INTERNAL
*/
public function setDefaultCellBorderPos(float $borderpos): void
{
if (
($borderpos == self::BORDERPOS_DEFAULT)
|| ($borderpos == self::BORDERPOS_EXTERNAL)
|| ($borderpos == self::BORDERPOS_INTERNAL)
) {
$this->defcell['borderpos'] = $borderpos;
return;
}
$this->defcell['borderpos'] = self::BORDERPOS_DEFAULT;
}
/**
* Increase the cell padding to account for the border tickness.
*
* @param array<int|string, StyleDataOpt> $styles Optional to overwrite the styles (see: getCurrentStyleArray).
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*
* @return TCellDef
*/
protected function adjustMinCellPadding(
array $styles = [],
?array $cell = null
): array {
if ($cell === null) {
$cell = $this->defcell;
}
if ($styles === []) {
$styles = $this->graph->getCurrentStyleArray();
}
$border_ratio = round(self::BORDERPOS_INTERNAL + $cell['borderpos'], 1);
$minT = 0;
$minR = 0;
$minB = 0;
$minL = 0;
if (! empty($styles['all']['lineWidth'])) {
$minT = $this->toPoints((float) $styles['all']['lineWidth'] * $border_ratio);
$minR = $minT;
$minB = $minT;
$minL = $minT;
} elseif (
(count($styles) == 4)
&& isset($styles[0]['lineWidth'])
&& isset($styles[1]['lineWidth'])
&& isset($styles[2]['lineWidth'])
&& isset($styles[3]['lineWidth'])
) {
$minT = $this->toPoints((float) $styles[0]['lineWidth'] * $border_ratio);
$minR = $this->toPoints((float) $styles[1]['lineWidth'] * $border_ratio);
$minB = $this->toPoints((float) $styles[2]['lineWidth'] * $border_ratio);
$minL = $this->toPoints((float) $styles[3]['lineWidth'] * $border_ratio);
} else {
return $cell;
}
$cell['padding']['T'] = max($cell['padding']['T'], $minT);
$cell['padding']['R'] = max($cell['padding']['R'], $minR);
$cell['padding']['B'] = max($cell['padding']['B'], $minB);
$cell['padding']['L'] = max($cell['padding']['L'], $minL);
return $cell;
}
/**
* Returns the minimum cell height in points for the current text height.
*
* @param float $pheight Text height in internal points.
* @param string $align Text vertical alignment inside the cell:
* - T=top;
* - C=center;
* - B=bottom;
* - A=center-on-font-ascent;
* - L=center-on-font-baseline;
* - D=center-on-font-descent.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellMinHeight(
float $pheight = 0,
string $align = 'C',
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
$curfont = $this->font->getCurrentFont();
if ($pheight == 0) {
$pheight = $curfont['height'];
}
return match ($align) {
'T', 'B' => ($pheight + $cell['padding']['T'] + $cell['padding']['B']),
'L' => ($pheight - $curfont['height'] + (2 * max(
($cell['padding']['T'] + $curfont['ascent']),
($cell['padding']['B'] - $curfont['descent'])
))),
'A', 'D' => ($pheight
- $curfont['height']
+ (2 * ($curfont['height'] + max($cell['padding']['T'], $cell['padding']['B'])))),
// default on 'C' case
default => ($pheight + (2 * max($cell['padding']['T'], $cell['padding']['B']))),
};
}
/**
* Returns the minimum cell width in points for the current text
*
* @param float $txtwidth Text width in internal points.
* @param string $align Cell horizontal alignment: L=left; C=center; R=right; J=Justify.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellMinWidth(
float $txtwidth,
string $align = 'L',
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
if ($align === '' || $align === 'J') { // Justify
$align = $this->rtl ? 'R' : 'L';
}
return match ($align) {
'C' => ceil($txtwidth + (2 * max($cell['padding']['L'], $cell['padding']['R']))),
default => ceil($txtwidth + $cell['padding']['L'] + $cell['padding']['R']),
};
}
/**
* Returns the adjusted cell top Y coordinate to account for margins.
*
* @param float $pnty Starting top Y coordinate in internal points.
* @param float $pheight Cell height in internal points.
* @param string $align Cell vertical alignment: T=top; C=center; B=bottom.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellVPos(
float $pnty,
float $pheight,
string $align = 'T',
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
return match ($align) {
'T' => $pnty - $cell['margin']['T'],
'C' => $pnty + ($pheight / 2),
'B' => $pnty + $cell['margin']['B'] + $pheight,
default => $pnty,
};
}
/**
* Returns the adjusted cell left X coordinate to account for margins.
*
* @param float $pntx Starting top Y coordinate in internal points.
* @param float $pwidth Cell width in internal points.
* @param string $align Cell horizontal alignment: L=left; C=center; R=right; J=Justify.
* @param TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellHPos(
float $pntx,
float $pwidth,
string $align = 'L',
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
if ($align === '' || $align === 'J') { // Justify
$align = $this->rtl ? 'R' : 'L';
}
return match ($align) {
'L' => $pntx + $cell['margin']['L'],
'R' => $pntx - $cell['margin']['R'] - $pwidth,
'C' => $pntx - ($pwidth / 2),
default => $pntx,
};
}
/**
* Returns the vertical distance between the cell top side and the text.
*
* @param float $cellpheight Cell height in internal points.
* @param float $txtpheight Text height in internal points.
* @param string $align Text vertical alignment inside the cell:
* - T=top;
* - C=center;
* - B=bottom;
* - A=center-on-font-ascent;
* - L=center-on-font-baseline;
* - D=center-on-font-descent.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellTextVAlign(
float $cellpheight,
float $txtpheight = 0,
string $align = 'C',
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
$curfont = $this->font->getCurrentFont();
if ($txtpheight == 0) {
$txtpheight = $curfont['height'];
}
return match ($align) {
'T' => ($cell['padding']['T']),
'B' => (($cellpheight - $txtpheight) - $cell['padding']['B']),
'L' => ((($cellpheight - $txtpheight + $curfont['height']) / 2) - $curfont['ascent']),
'A' => (($cellpheight - $txtpheight + $curfont['height']) / 2),
'D' => ((($cellpheight - $txtpheight + $curfont['height']) / 2) - $curfont['height']),
// default on 'C' case
default => (($cellpheight - $txtpheight) / 2)
};
}
/**
* Returns the horizontal distance between the cell left side and the text left side.
*
* @param float $pwidth Cell width in internal points.
* @param float $txtpwidth Text width in internal points.
* @param string $align Text horizontal alignment inside the cell: L=left; C=center; R=right; J=Justify.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellTextHAlign(
float $pwidth,
float $txtpwidth,
string $align = 'L',
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
if ($align === '' || $align === 'J') { // Justify
$align = $this->rtl ? 'R' : 'L';
}
return match ($align) {
'C' => (($pwidth - $txtpwidth) / 2),
'R' => ($pwidth - $cell['padding']['R'] - $txtpwidth),
// default on 'L' case
default => ($cell['padding']['L']),
};
}
/**
* Returns the top Y coordinate of the cell wrapping the text.
*
* @param float $txty Text baseline top Y coordinate in internal points.
* @param float $cellpheight Cell height in internal points.
* @param float $txtpheight Text height in internal points.
* @param string $align Text vertical alignment inside the cell:
* - T=top;
* - C=center;
* - B=bottom;
* - A=center-on-font-ascent;
* - L=center-on-font-baseline;
* - D=center-on-font-descent.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellVPosFromText(
float $txty,
float $cellpheight,
float $txtpheight = 0,
string $align = 'C',
?array $cell = null
): float {
return ($txty + $this->cellTextVAlign($cellpheight, $txtpheight, $align, $cell));
}
/**
* Returns the left X coordinate of the cell wrapping the text.
*
* @param float $txtx Text left X coordinate in internal points.
* @param float $pwidth Cell width in internal points.
* @param float $txtpwidth Text width in internal points.
* @param string $align Text horizontal alignment inside the cell: L=left; C=center; R=right.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function cellHPosFromText(
float $txtx,
float $pwidth,
float $txtpwidth,
string $align = 'L',
?array $cell = null
): float {
return ($txtx - $this->cellTextHAlign($pwidth, $txtpwidth, $align, $cell));
}
/**
* Returns the top Y coordinate of the text inside the cell.
*
* @param float $pnty Cell top Y coordinate in internal points.
* @param float $cellpheight Cell height in internal points.
* @param float $txtpheight Text height in internal points.
* @param string $align Text vertical alignment inside the cell:
* - T=top;
* - C=center;
* - B=bottom;
* - A=center-on-font-ascent;
* - L=center-on-font-baseline;
* - D=center-on-font-descent.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function textVPosFromCell(
float $pnty,
float $cellpheight,
float $txtpheight = 0,
string $align = 'C',
?array $cell = null
): float {
return ($pnty - $this->cellTextVAlign($cellpheight, $txtpheight, $align, $cell));
}
/**
* Returns the left X coordinate of the text inside the cell.
*
* @param float $pntx Cell left X coordinate in internal points.
* @param float $pwidth Cell width in internal points.
* @param float $txtpwidth Text width in internal points.
* @param string $align Text horizontal alignment inside the cell: L=left; C=center; R=right.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*/
protected function textHPosFromCell(
float $pntx,
float $pwidth,
float $txtpwidth,
string $align = 'L',
?array $cell = null
): float {
return ($pntx + $this->cellTextHAlign($pwidth, $txtpwidth, $align, $cell));
}
/**
* Calculates the maximum width available for a cell that fits the current region width.
*
* @param float $pntx Cell left X coordinate in internal points.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*
* @return float
*/
protected function cellMaxWidth(
float $pntx = 0,
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
$region = $this->page->getRegion();
return ($this->toPoints($region['RW']) - $pntx - $cell['margin']['L'] - $cell['margin']['R']);
}
/**
* Calculates the maximum width available for text within a cell.
*
* @param float $pwidth Cell width in internal points.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*
* @return float The maximum width available for text within the cell.
*/
protected function textMaxWidth(
float $pwidth,
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
return ($pwidth - $cell['padding']['L'] - $cell['padding']['R']);
}
/**
* Calculates the maximum height available for text within a cell.
*
* @param float $pheight Available vertical space in internal points.
* @param string $align Text vertical alignment inside the cell:
* - T=top;
* - C=center;
* - B=bottom;
* - A=center-on-font-ascent;
* - L=center-on-font-baseline;
* - D=center-on-font-descent.
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*
* @return float The maximum width available for text within the cell.
*/
protected function textMaxHeight(
float $pheight,
string $align = 'T',
?array $cell = null
): float {
if ($cell === null) {
$cell = $this->defcell;
}
$curfont = $this->font->getCurrentFont();
$cph = ($pheight - $cell['margin']['T'] - $cell['margin']['B']);
// Use a match expression to determine the maximum text height based on alignment.
return match ($align) {
// Top or Bottom
'T', 'B' => ($cph - $cell['padding']['T'] - $cell['padding']['B']),
// Center on font Baseline
'L' => ($cph + $curfont['height'] - (2 * max(
($cell['padding']['T'] + $curfont['ascent']),
($cell['padding']['B'] - $curfont['descent'])
))),
// Center on font Ascent or Descent
'A', 'D' => ($cph
+ $curfont['height']
- (2 * ($curfont['height'] + max($cell['padding']['T'], $cell['padding']['B'])))),
// Default to Center 'C' case
default => ($cph - (2 * max($cell['padding']['T'], $cell['padding']['B']))),
};
}
/**
* Returns the PDF code to draw the text cell border and background.
*
* @param float $pntx Cell left X coordinate in internal points.
* @param float $pnty Cell top Y coordinate in internal points.
* @param float $pwidth Cell width in internal points.
* @param float $pheight Cell height in internal points.
* @param array<int|string, StyleDataOpt> $styles Optional to overwrite the styles (see: getCurrentStyleArray).
* @param ?TCellDef $cell Optional to overwrite cell parameters for padding, margin etc.
*
* @return string
*/
protected function drawCell(
float $pntx,
float $pnty,
float $pwidth,
float $pheight,
array $styles = [],
?array $cell = null
) {
$drawfill = (!empty($styles['all']['fillColor']));
$drawborder = (
!empty($styles['all']['lineWidth'])
|| !empty($styles[0]['lineWidth'])
|| !empty($styles[1]['lineWidth'])
|| !empty($styles[2]['lineWidth'])
|| !empty($styles[3]['lineWidth'])
);
if (!$drawfill && !$drawborder) {
return '';
}
if ($cell === null) {
$cell = $this->defcell;
}
$styleall = (empty($styles['all']) ? [] : $styles['all']);
$out = $this->graph->getStartTransform();
$stoptr = $this->graph->getStopTransform();
if (
$drawfill
&& $drawborder
&& ($cell['borderpos'] == self::BORDERPOS_DEFAULT)
&& (count($styles) <= 1)
) {
// single default border style for all sides
$out .= $this->graph->getBasicRect(
$this->toUnit($pntx),
$this->toYUnit($pnty),
$this->toUnit($pwidth),
$this->toUnit($pheight),
'b', // close, fill, and then stroke the path
$styleall,
);
return $out . $stoptr;
}
if ($drawfill) {
$out .= $this->graph->getBasicRect(
$this->toUnit($pntx),
$this->toYUnit($pnty),
$this->toUnit($pwidth),
$this->toUnit($pheight),
'f', // fill the path
$styleall,
);
}
if (!$drawborder) {
return $out . $stoptr;
}
$adj = (isset($styles['all']['lineWidth'])
? $this->toPoints((float) $styles['all']['lineWidth'] * $cell['borderpos'])
: 0);
$adjx = (isset($styles['3']['lineWidth'])
? $this->toPoints((float) $styles['3']['lineWidth'] * $cell['borderpos'])
: $adj);
$adjy = isset($styles['0']['lineWidth'])
? $this->toPoints((float) $styles['0']['lineWidth'] * $cell['borderpos'])
: $adj;
$adjw = $adjx + (isset($styles['1']['lineWidth'])
? $this->toPoints((float) $styles['1']['lineWidth'] * $cell['borderpos'])
: $adj);
$adjh = $adjy + (isset($styles['2']['lineWidth'])
? $this->toPoints((float) $styles['2']['lineWidth'] * $cell['borderpos'])
: $adj);
// different border styles for each side
$out .= $this->graph->getRect(
$this->toUnit($pntx + $adjx),
$this->toYUnit($pnty - $adjy),
$this->toUnit($pwidth - $adjw),
$this->toUnit($pheight - $adjh),
's', // close and stroke the path
$styles,
);
return $out . $stoptr;
}
}

View File

@@ -0,0 +1,105 @@
<?php
/**
* ClassObjects.php
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
use Com\Tecnick\Barcode\Barcode as ObjBarcode;
use Com\Tecnick\Color\Pdf as ObjColor;
use Com\Tecnick\File\Cache as ObjCache;
use Com\Tecnick\File\File as ObjFile;
use Com\Tecnick\Pdf\Encrypt\Encrypt as ObjEncrypt;
use Com\Tecnick\Pdf\Font\Stack as ObjFont;
use Com\Tecnick\Pdf\Graph\Draw as ObjGraph;
use Com\Tecnick\Pdf\Image\Import as ObjImage;
use Com\Tecnick\Pdf\Page\Page as ObjPage;
use Com\Tecnick\Unicode\Convert as ObjUniConvert;
/**
* Com\Tecnick\Pdf\ClassObjects
*
* External class objects PDF class
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* @SuppressWarnings("PHPMD.DepthOfInheritance")
*/
abstract class ClassObjects extends \Com\Tecnick\Pdf\Output
{
/**
* Initialize dependencies class objects.
*
* @param ?ObjEncrypt $objEncrypt Encryption object.
*/
public function initClassObjects(
?ObjEncrypt $objEncrypt = null
): void {
if ($objEncrypt instanceof ObjEncrypt) {
$this->encrypt = $objEncrypt;
} else {
$this->encrypt = new ObjEncrypt();
}
$this->color = new ObjColor();
$this->barcode = new ObjBarcode();
$this->file = new ObjFile();
$this->cache = new ObjCache();
$this->uniconv = new ObjUniConvert();
$pdfamode = (bool) ($this->pdfa > 0);
$this->page = new ObjPage(
$this->unit,
$this->color,
$this->encrypt,
$pdfamode,
$this->compress,
$this->sigapp,
);
$this->kunit = $this->page->getKUnit();
$this->svgminunitlen = $this->toUnit($this::SVGMINPNTLEN);
$this->graph = new ObjGraph(
$this->kunit,
0, // $this->graph->setPageWidth($pagew)
0, // $this->graph->setPageHeight($pageh)
$this->color,
$this->encrypt,
$pdfamode,
$this->compress,
);
$this->font = new ObjFont(
$this->kunit,
$this->subsetfont,
$this->isunicode,
$pdfamode,
);
$this->image = new ObjImage(
$this->kunit,
$this->encrypt,
$pdfamode,
$this->compress,
);
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Exception.php
*
* @since 2015-02-21
* @category Library
* @package PDF
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2015-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
/**
* Com\Tecnick\Pdf\Exception
*
* Custom Exception class
*
* @since 2015-02-21
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2015-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*/
class Exception extends \Exception
{
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* HTML.php
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
use Com\Tecnick\Pdf\Exception as PdfException;
/**
* Com\Tecnick\Pdf\HTML
*
* HTML PDF class
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*/
abstract class HTML extends \Com\Tecnick\Pdf\CSS
{
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* JavaScript.php
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
use Com\Tecnick\Pdf\Exception as PdfException;
/**
* Com\Tecnick\Pdf\JavaScript
*
* JavaScript PDF class
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* @SuppressWarnings("PHPMD.DepthOfInheritance")
*/
abstract class JavaScript extends \Com\Tecnick\Pdf\HTML
{
}

View File

@@ -0,0 +1,593 @@
<?php
/**
* MetaInfo.php
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
namespace Com\Tecnick\Pdf;
use Com\Tecnick\Pdf\Exception as PdfException;
/**
* Com\Tecnick\Pdf\MetaInfo
*
* Meta Informaton PDF class
*
* @since 2002-08-03
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2025 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* @phpstan-import-type TViewerPref from Base
*
* @SuppressWarnings("PHPMD.DepthOfInheritance")
*/
abstract class MetaInfo extends \Com\Tecnick\Pdf\JavaScript
{
/**
* Valid document zoom modes
*
* @var array<string>
*/
protected const VALIDZOOM = ['fullpage', 'fullwidth', 'real', 'default'];
/**
* Return the program version.
*/
public function getVersion(): string
{
return $this->version;
}
/**
* Set a field value only if it is not empty.
*
* @param string $field Field name
* @param string $value Value to set
*/
private function setNonEmptyFieldValue(string $field, string $value): static
{
if ($value !== '') {
$this->$field = $value;
}
return $this;
}
/**
* Set the value of an existing array key if it is not empty.
*
* @param string $field Field array name
* @param string $key Key name
* @param string $value Value to set
*/
private function setNonEmptyArrayFieldValue(string $field, string $key, string $value): static
{
if (
isset($this->$field)
&& is_array($this->$field)
&& ($key !== '')
&& isset($this->$field[$key])
&& ($value !== '')
) {
$this->$field[$key] = $value;
}
return $this;
}
/**
* Defines the creator of the document.
* This is typically the name of the application that generates the PDF.
*
* @param string $creator The name of the creator.
*/
public function setCreator(string $creator): static
{
return $this->setNonEmptyFieldValue('creator', $creator);
}
/**
* Defines the author of the document.
*
* @param string $author The name of the author.
*/
public function setAuthor(string $author): static
{
return $this->setNonEmptyFieldValue('author', $author);
}
/**
* Defines the subject of the document.
*
* @param string $subject The subject.
*/
public function setSubject(string $subject): static
{
return $this->setNonEmptyFieldValue('subject', $subject);
}
/**
* Defines the title of the document.
*
* @param string $title The title.
*/
public function setTitle(string $title): static
{
return $this->setNonEmptyFieldValue('title', $title);
}
/**
* Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'.
*
* @param string $keywords Space-separated list of keywords.
*/
public function setKeywords(string $keywords): static
{
return $this->setNonEmptyFieldValue('keywords', $keywords);
}
/**
* Set the PDF version (check PDF reference for valid values).
*
* @param string $version PDF document version.
*
* @throw PdfException in case of error.
*/
public function setPDFVersion(string $version = '1.7'): static
{
if ($this->pdfa == 1) { // PDF/A 1 mode
$this->pdfver = '1.4';
return $this;
}
$isvalid = preg_match('/^[1-9]+[.]\d+$/', $version);
if ($isvalid === false) {
throw new PdfException('Invalid PDF version format');
}
$this->pdfver = $version;
return $this;
}
/**
* Set the sRGB mode
*
* @param bool $enabled Set to true to add the default sRGB ICC color profile
*/
public function setSRGB(bool $enabled): static
{
$this->sRGB = $enabled;
return $this;
}
/**
* Format a text string for output.
*
* @param string $str String to escape.
* @param int $oid Current PDF object number.
* @param bool $bom If true set the Byte Order Mark (BOM).
*
* @return string escaped string.
*/
protected function getOutTextString(
string $str,
int $oid,
bool $bom = false
): string {
if ($this->isunicode) {
$str = $this->uniconv->toUTF16BE($str);
if ($bom) {
$str = "\xFE\xFF" . $str; // Byte Order Mark (BOM)
}
}
return $this->encrypt->escapeDataString($str, $oid);
}
/**
* Returns a formatted date for meta information
*
* @param int $time Time in seconds.
*
* @return string date-time string.
*/
protected function getFormattedDate(int $time): string
{
return substr_replace(date('YmdHisO', $time), "'", (-2), 0) . "'";
}
/**
* Returns a formatted date for XMP meta information
*
* @param int $time Time in seconds.
*
* @return string date-time string.
*/
protected function getXMPFormattedDate(int $time): string
{
return date('Y-m-dTH:i:sP', $time);
}
/**
* Returns the producer string
*/
protected function getProducer(): string
{
return "\x54\x43\x50\x44\x46\x20"
. $this->version
. "\x20\x28\x68\x74\x74\x70\x73\x3a\x2f\x2f"
. "\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29";
}
/**
* Returns a formatted date for meta information
*
* @param int $time Time in seconds.
* @param int $oid Current PDF object number.
*
* @return string escaped date-time string.
*/
protected function getOutDateTimeString(int $time, int $oid): string
{
if ($time === 0) {
$time = $this->doctime;
}
return $this->encrypt->escapeDataString('D:' . $this->getFormattedDate($time), $oid);
}
/**
* Get the PDF output string for the Document Information Dictionary.
* (ref. Chapter 14.3.3 Document Information Dictionary of PDF32000_2008.pdf)
*/
protected function getOutMetaInfo(): string
{
$oid = ++$this->pon;
$this->objid['info'] = $oid;
return $oid . ' 0 obj' . "\n"
. '<<'
. ' /Creator ' . $this->getOutTextString($this->creator, $oid, true)
. ' /Author ' . $this->getOutTextString($this->author, $oid, true)
. ' /Subject ' . $this->getOutTextString($this->subject, $oid, true)
. ' /Title ' . $this->getOutTextString($this->title, $oid, true)
. ' /Keywords ' . $this->getOutTextString($this->keywords, $oid, true)
. ' /Producer ' . $this->getOutTextString($this->getProducer(), $oid, true)
. ' /CreationDate ' . $this->getOutDateTimeString($this->doctime, $oid)
. ' /ModDate ' . $this->getOutDateTimeString($this->docmodtime, $oid)
. ' /Trapped /False'
. ' >>' . "\n"
. 'endobj' . "\n";
}
/**
* Escape some special characters (&lt; &gt; &amp;) for XML output.
*
* @param string $str Input string to escape.
*/
protected function getEscapedXML(string $str): string
{
return strtr($str, [
"\0" => '',
'&' => '&amp;',
'<' => '&lt;',
'>' => '&gt;',
]);
}
/**
* Set additional custom XMP data to be appended just before the end of the tag indicated by the key.
*
* IMPORTANT:
* This data is added as-is without controls, so you have to validate your data before using this method.
*
* @param string $key Key for the custom XMP data. Valid keys are:
* - 'x:xmpmeta'
* - 'x:xmpmeta.rdf:RDF'
* - 'x:xmpmeta.rdf:RDF.rdf:Description'
* - 'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas'
* - 'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas.rdf:Bag'
* @param string $xmp Custom XMP data.
*/
public function setCustomXMP(string $key, string $xmp): static
{
return $this->setNonEmptyArrayFieldValue('custom_xmp', $key, $xmp);
}
/**
* Get the PDF output string for the XMP data object
*
* @SuppressWarnings("PHPMD.ExcessiveMethodLength")
*/
protected function getOutXMP(): string
{
$uuid = 'uuid:' . substr($this->fileid, 0, 8)
. '-' . substr($this->fileid, 8, 4)
. '-' . substr($this->fileid, 12, 4)
. '-' . substr($this->fileid, 16, 4)
. '-' . substr($this->fileid, 20, 12);
// @codingStandardsIgnoreStart
$xmp = '<?xpacket begin="' . $this->uniconv->chr(0xfeff) . '" id="W5M0MpCehiHzreSzNTczkc9d"?>' . "\n"
. '<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.1-c043 52.372728, 2009/01/18-15:08:04">' . "\n"
. "\t" . '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">' . "\n"
. "\t\t" . '<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">' . "\n"
. "\t\t\t" . '<dc:format>application/pdf</dc:format>' . "\n"
. "\t\t\t" . '<dc:title>' . "\n"
. "\t\t\t\t" . '<rdf:Alt>' . "\n"
. "\t\t\t\t\t" . '<rdf:li xml:lang="x-default">' . $this->getEscapedXML($this->title) . '</rdf:li>' . "\n"
. "\t\t\t\t" . '</rdf:Alt>' . "\n"
. "\t\t\t" . '</dc:title>' . "\n"
. "\t\t\t" . '<dc:creator>' . "\n"
. "\t\t\t\t" . '<rdf:Seq>' . "\n"
. "\t\t\t\t\t" . '<rdf:li>' . $this->getEscapedXML($this->author) . '</rdf:li>' . "\n"
. "\t\t\t\t" . '</rdf:Seq>' . "\n"
. "\t\t\t" . '</dc:creator>' . "\n"
. "\t\t\t" . '<dc:description>' . "\n"
. "\t\t\t\t" . '<rdf:Alt>' . "\n"
. "\t\t\t\t\t" . '<rdf:li xml:lang="x-default">' . $this->getEscapedXML($this->subject) . '</rdf:li>' . "\n"
. "\t\t\t\t" . '</rdf:Alt>' . "\n"
. "\t\t\t" . '</dc:description>' . "\n"
. "\t\t\t" . '<dc:subject>' . "\n"
. "\t\t\t\t" . '<rdf:Bag>' . "\n"
. "\t\t\t\t\t" . '<rdf:li>' . $this->getEscapedXML($this->keywords) . '</rdf:li>' . "\n"
. "\t\t\t\t" . '</rdf:Bag>' . "\n"
. "\t\t\t" . '</dc:subject>' . "\n"
. "\t\t" . '</rdf:Description>' . "\n"
. "\t\t" . '<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">' . "\n"
. "\t\t\t" . '<xmp:CreateDate>' . $this->getXMPFormattedDate($this->doctime) . '</xmp:CreateDate>' . "\n"
. "\t\t\t" . '<xmp:CreatorTool>' . $this->getEscapedXML($this->creator) . '</xmp:CreatorTool>' . "\n"
. "\t\t\t" . '<xmp:ModifyDate>' . $this->getXMPFormattedDate($this->docmodtime) . '</xmp:ModifyDate>' . "\n"
. "\t\t\t" . '<xmp:MetadataDate>' . $this->getXMPFormattedDate($this->doctime) . '</xmp:MetadataDate>' . "\n"
. "\t\t" . '</rdf:Description>' . "\n"
. "\t\t" . '<rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">' . "\n"
. "\t\t\t" . '<pdf:Keywords>' . $this->getEscapedXML($this->keywords) . '</pdf:Keywords>' . "\n"
. "\t\t\t" . '<pdf:Producer>' . $this->getEscapedXML($this->getProducer()) . '</pdf:Producer>' . "\n"
. "\t\t" . '</rdf:Description>' . "\n"
. "\t\t" . '<rdf:Description rdf:about="" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/">' . "\n"
. "\t\t\t" . '<xmpMM:DocumentID>' . $uuid . '</xmpMM:DocumentID>' . "\n"
. "\t\t\t" . '<xmpMM:InstanceID>' . $uuid . '</xmpMM:InstanceID>' . "\n"
. "\t\t" . '</rdf:Description>' . "\n";
if ($this->pdfa !== 0) {
$xmp .= ' <rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">' . "\n"
. "\t\t\t" . '<pdfaid:part>' . $this->pdfa . '</pdfaid:part>' . "\n"
. "\t\t\t" . '<pdfaid:conformance>B</pdfaid:conformance>' . "\n"
. "\t\t" . '</rdf:Description>' . "\n";
}
// XMP extension schemas
$xmp .= "\t\t" . '<rdf:Description rdf:about="" xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/" xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#" xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">' . "\n"
. "\t\t\t" . '<pdfaExtension:schemas>' . "\n"
. "\t\t\t\t" . '<rdf:Bag>' . "\n"
. "\t\t\t\t\t" . '<rdf:li rdf:parseType="Resource">' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:namespaceURI>http://ns.adobe.com/pdf/1.3/</pdfaSchema:namespaceURI>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:prefix>pdf</pdfaSchema:prefix>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:schema>Adobe PDF Schema</pdfaSchema:schema>' . "\n"
. "\t\t\t\t\t" . '</rdf:li>' . "\n"
. "\t\t\t\t\t" . '<rdf:li rdf:parseType="Resource">' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:namespaceURI>http://ns.adobe.com/xap/1.0/mm/</pdfaSchema:namespaceURI>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:prefix>xmpMM</pdfaSchema:prefix>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:schema>XMP Media Management Schema</pdfaSchema:schema>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:property>' . "\n"
. "\t\t\t\t\t\t\t" . '<rdf:Seq>' . "\n"
. "\t\t\t\t\t\t\t\t" . '<rdf:li rdf:parseType="Resource">' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:category>internal</pdfaProperty:category>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:description>UUID based identifier for specific incarnation of a document</pdfaProperty:description>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:name>InstanceID</pdfaProperty:name>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:valueType>URI</pdfaProperty:valueType>' . "\n"
. "\t\t\t\t\t\t\t\t" . '</rdf:li>' . "\n"
. "\t\t\t\t\t\t\t" . '</rdf:Seq>' . "\n"
. "\t\t\t\t\t\t" . '</pdfaSchema:property>' . "\n"
. "\t\t\t\t\t" . '</rdf:li>' . "\n"
. "\t\t\t\t\t" . '<rdf:li rdf:parseType="Resource">' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:namespaceURI>http://www.aiim.org/pdfa/ns/id/</pdfaSchema:namespaceURI>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:prefix>pdfaid</pdfaSchema:prefix>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:schema>PDF/A ID Schema</pdfaSchema:schema>' . "\n"
. "\t\t\t\t\t\t" . '<pdfaSchema:property>' . "\n"
. "\t\t\t\t\t\t\t" . '<rdf:Seq>' . "\n"
. "\t\t\t\t\t\t\t\t" . '<rdf:li rdf:parseType="Resource">' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:category>internal</pdfaProperty:category>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:description>Part of PDF/A standard</pdfaProperty:description>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:name>part</pdfaProperty:name>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:valueType>Integer</pdfaProperty:valueType>' . "\n"
. "\t\t\t\t\t\t\t\t" . '</rdf:li>' . "\n"
. "\t\t\t\t\t\t\t\t" . '<rdf:li rdf:parseType="Resource">' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:category>internal</pdfaProperty:category>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:description>Amendment of PDF/A standard</pdfaProperty:description>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:name>amd</pdfaProperty:name>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:valueType>Text</pdfaProperty:valueType>' . "\n"
. "\t\t\t\t\t\t\t\t" . '</rdf:li>' . "\n"
. "\t\t\t\t\t\t\t\t" . '<rdf:li rdf:parseType="Resource">' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:category>internal</pdfaProperty:category>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:description>Conformance level of PDF/A standard</pdfaProperty:description>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:name>conformance</pdfaProperty:name>' . "\n"
. "\t\t\t\t\t\t\t\t\t" . '<pdfaProperty:valueType>Text</pdfaProperty:valueType>' . "\n"
. "\t\t\t\t\t\t\t\t" . '</rdf:li>' . "\n"
. "\t\t\t\t\t\t\t" . '</rdf:Seq>' . "\n"
. "\t\t\t\t\t\t" . '</pdfaSchema:property>' . "\n"
. "\t\t\t\t\t" . '</rdf:li>' . "\n"
. $this->custom_xmp['x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas.rdf:Bag'] . "\n"
. "\t\t\t\t" . '</rdf:Bag>' . "\n"
. $this->custom_xmp['x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas'] . "\n"
. "\t\t\t" . '</pdfaExtension:schemas>' . "\n"
. $this->custom_xmp['x:xmpmeta.rdf:RDF.rdf:Description'] . "\n"
. "\t\t" . '</rdf:Description>' . "\n"
. $this->custom_xmp['x:xmpmeta.rdf:RDF'] . "\n"
. "\t" . '</rdf:RDF>' . "\n"
. $this->custom_xmp['x:xmpmeta'] . "\n"
. '</x:xmpmeta>' . "\n"
. '<?xpacket end="w"?>';
// @codingStandardsIgnoreEnd
$oid = ++$this->pon;
$this->objid['xmp'] = $oid;
return $oid . ' 0 obj' . "\n"
. '<<'
. ' /Type /Metadata'
. ' /Subtype /XML'
. ' /Length ' . strlen($xmp)
. ' >> stream' . "\n"
. $xmp . "\n"
. 'endstream' . "\n"
. 'endobj' . "\n";
}
/**
* Set the default document language direction.
*
* @param bool $enabled False = LTR = Left-To-Right; True = RTL = Right-To-Left.
*/
public function setRTL(bool $enabled): static
{
$this->rtl = $enabled;
return $this;
}
/**
* Set the viewer preferences dictionary
* controlling the way the document is to be presented on the screen or in print.
*
* @param TViewerPref $pref Array of options (see PDF reference "Viewer Preferences").
*/
public function setViewerPreferences(array $pref): static
{
$this->viewerpref = $pref;
return $this;
}
/**
* Sanitize the page box name and return the default 'CropBox' in case of error.
*
* @param string $name Entry name.
*/
protected function getPageBoxName(string $name): string
{
$box = 'CropBox';
if (isset($this->viewerpref[$name])) {
$val = $this->viewerpref[$name];
if (
isset($this->page->$box[$val]) // @phpstan-ignore offsetAccess.nonOffsetAccessible
&& is_string($this->page->$box[$val])
) {
$box = $this->page->$box[$val];
}
}
return ' /' . $name . ' /' . $box;
}
/**
* Sanitize the page box name and return the default 'CropBox' in case of error.
*/
protected function getPagePrintScaling(): string
{
$mode = 'AppDefault';
if (isset($this->viewerpref['PrintScaling'])) {
$name = strtolower($this->viewerpref['PrintScaling']);
$valid = [
'none' => 'None',
'appdefault' => 'AppDefault',
];
if (isset($valid[$name])) {
$mode = $valid[$name];
}
}
return ' /PrintScaling /' . $mode;
}
/**
* Returns the Duplex mode for the Viewer Preferences
*/
protected function getDuplexMode(): string
{
if (isset($this->viewerpref['Duplex'])) {
$name = strtolower($this->viewerpref['Duplex']);
$valid = [
'simplex' => 'Simplex',
'duplexflipshortedge' => 'DuplexFlipShortEdge',
'duplexfliplongedge' => 'DuplexFlipLongEdge',
];
if (isset($valid[$name])) {
return ' /Duplex /' . $valid[$name];
}
}
return '';
}
/**
* Returns the Viewer Preference boolean entry.
*
* @param string $name Entry name.
*/
protected function getBooleanMode(string $name): string
{
if (isset($this->viewerpref[$name])) {
return ' /' . $name . ' ' . ($this->viewerpref[$name] === true ? 'true' : 'false');
}
return '';
}
/**
* Returns the PDF viewer preferences for the catalog section
*/
protected function getOutViewerPref(): string
{
$vpr = $this->viewerpref;
$out = ' /ViewerPreferences <<';
if ($this->rtl) {
$out .= ' /Direction /R2L';
} else {
$out .= ' /Direction /L2R';
}
$out .= $this->getBooleanMode('HideToolbar');
$out .= $this->getBooleanMode('HideMenubar');
$out .= $this->getBooleanMode('HideWindowUI');
$out .= $this->getBooleanMode('FitWindow');
$out .= $this->getBooleanMode('CenterWindow');
$out .= $this->getBooleanMode('DisplayDocTitle');
if (isset($vpr['NonFullScreenPageMode'])) {
$out .= ' /NonFullScreenPageMode /' . $this->page->getDisplay($vpr['NonFullScreenPageMode']);
}
$out .= $this->getPageBoxName('ViewArea');
$out .= $this->getPageBoxName('ViewClip');
$out .= $this->getPageBoxName('PrintArea');
$out .= $this->getPageBoxName('PrintClip');
$out .= $this->getPagePrintScaling();
$out .= $this->getDuplexMode();
$out .= $this->getBooleanMode('PickTrayByPDFSize');
if (isset($vpr['PrintPageRange'])) {
$PrintPageRangeNum = '';
foreach ($vpr['PrintPageRange'] as $pnum) {
$PrintPageRangeNum .= ' ' . ($pnum - 1) . '';
}
$out .= ' /PrintPageRange [' . $PrintPageRangeNum . ' ]';
}
if (isset($vpr['NumCopies'])) {
$out .= ' /NumCopies ' . (int) $vpr['NumCopies'];
}
return $out . ' >>';
}
}

File diff suppressed because it is too large Load Diff

2603
vendor/tecnickcom/tc-lib-pdf/src/SVG.php vendored Normal file

File diff suppressed because it is too large Load Diff

1276
vendor/tecnickcom/tc-lib-pdf/src/Tcpdf.php vendored Normal file

File diff suppressed because it is too large Load Diff

1703
vendor/tecnickcom/tc-lib-pdf/src/Text.php vendored Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.