added composer files and installed vendor packages. Also modified xsls to display base project
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E000_overview.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example_overview.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 000');
|
||||
$pdf->setTitle('tc-lib-pdf Visual Showcase');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf showcase barcode qr svg image transparency gradients');
|
||||
$pdf->setPDFFilename('000_overview.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$titleFont = $pdf->font->insert($pdf->pon, 'dejavusans', 'B', 30);
|
||||
$subtitleFont = $pdf->font->insert($pdf->pon, 'dejavusans', '', 13);
|
||||
$bodyFont = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
$smallFont = $pdf->font->insert($pdf->pon, 'dejavusans', '', 8);
|
||||
|
||||
$imgdir = __DIR__ . '/images';
|
||||
|
||||
// ----------
|
||||
// Add first page
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Visual showcase', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'blue');
|
||||
|
||||
$pageW = (float) $page01['width'];
|
||||
$pageH = (float) $page01['height'];
|
||||
|
||||
$cardStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.35,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'rgb(193,216,242)',
|
||||
'fillColor' => 'rgb(255,255,255)',
|
||||
],
|
||||
];
|
||||
|
||||
$lineStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.25,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'rgb(147,196,227)',
|
||||
'fillColor' => 'rgb(147,196,227)',
|
||||
],
|
||||
];
|
||||
|
||||
$barcodeStyle = [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'black',
|
||||
'fillColor' => 'black',
|
||||
];
|
||||
|
||||
$textOnDark = $pdf->color->getPdfColor('rgb(244,250,255)');
|
||||
$textOnLight = $pdf->color->getPdfColor('rgb(22,37,61)');
|
||||
|
||||
// Background atmosphere.
|
||||
$pdf->page->addContent($pdf->graph->getLinearGradient(0, 0, $pageW, $pageH, 'rgb(10,27,60)', 'rgb(0,171,193)', [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
]));
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(0.12));
|
||||
for ($lineY = -20; $lineY <= 330; $lineY += 12) {
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, (float) $lineY, $pageW, (float) ($lineY + 95), $lineStyle));
|
||||
}
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(0.28));
|
||||
$pdf->page->addContent($pdf->graph->getCircle(167, 46, 40, 0, 360, 'F', [
|
||||
'all' => [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'rgb(255,255,255)',
|
||||
'fillColor' => 'rgb(255,255,255)',
|
||||
],
|
||||
]));
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(1.0));
|
||||
|
||||
// Main title block.
|
||||
$pdf->page->addContent($textOnDark);
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<div style="font-size:30pt; font-weight:bold; color:rgb(244,250,255);">tc-lib-pdf</div>',
|
||||
posx: 15,
|
||||
posy: 18,
|
||||
width: 120,
|
||||
);
|
||||
|
||||
$pdf->page->addContent($subtitleFont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<div style="font-size:13pt; line-height:1.3; color:rgb(244,250,255);">Modern PDF generation in pure PHP: vectors, images, barcodes, and rich page composition.</div>',
|
||||
posx: 15,
|
||||
posy: 34,
|
||||
width: 125,
|
||||
);
|
||||
|
||||
// Left feature card.
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(0.90));
|
||||
$pdf->page->addContent($pdf->graph->getRect(12, 56, 89, 137, 'DF', $cardStyle));
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(1.0));
|
||||
|
||||
$pdf->page->addContent($textOnLight);
|
||||
$pdf->page->addContent($subtitleFont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<div style="font-size:13pt; color:rgb(22,37,61);">Cool Features</div>',
|
||||
posx: 18,
|
||||
posy: 64,
|
||||
width: 72,
|
||||
);
|
||||
|
||||
$pdf->page->addContent($bodyFont['out']);
|
||||
$features =
|
||||
'<ul style="font-size:10pt; color:rgb(22,37,61); margin:0; padding-left:12pt;">'
|
||||
. '<li>Native SVG rendering</li>'
|
||||
. '<li>JPEG/PNG with transparency</li>'
|
||||
. '<li>1D/2D barcodes (QR, DataMatrix)</li>'
|
||||
. '<li>Gradients and vector primitives</li>'
|
||||
. '<li>HTML/CSS text layout</li>'
|
||||
. '<li>Digital signatures and PDF/X, PDF/UA support</li>'
|
||||
. '</ul>';
|
||||
$pdf->addHTMLCell(html: $features, posx: 18, posy: 74, width: 79);
|
||||
|
||||
$logoFile = $imgdir . '/tcpdf_logo.jpg';
|
||||
if (\is_file($logoFile)) {
|
||||
$logoId = $pdf->image->add($logoFile);
|
||||
$pdf->page->addContent($pdf->image->getSetImage($logoId, 153, 10, 40, 13, $pageH));
|
||||
}
|
||||
|
||||
// SVG art panel.
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(0.92));
|
||||
$pdf->page->addContent($pdf->graph->getRect(106, 70, 92, 121, 'DF', $cardStyle));
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(1.0));
|
||||
|
||||
$svgFile = $imgdir . '/testsvgblend.svg';
|
||||
if (\is_file($svgFile)) {
|
||||
$svgObj = $pdf->addSVG(img: $svgFile, posx: 111, posy: 76, width: 82, height: 108, pageheight: $pageH);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svgObj));
|
||||
}
|
||||
|
||||
$pdf->page->addContent($textOnLight);
|
||||
$pdf->page->addContent($smallFont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<div style="font-size:8pt; text-align:center; color:rgb(22,37,61);">SVG graphic rendered directly into PDF vectors</div>',
|
||||
posx: 111,
|
||||
posy: 182,
|
||||
width: 82,
|
||||
);
|
||||
|
||||
// QR code panel.
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(0.92));
|
||||
$pdf->page->addContent($pdf->graph->getRect(12, 198, 186, 76, 'DF', $cardStyle));
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(1.0));
|
||||
|
||||
$pdf->page->addContent($textOnLight);
|
||||
$pdf->page->addContent($subtitleFont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<div style="font-size:13pt; color:rgb(22,37,61);">Scan to Explore</div>',
|
||||
posx: 18,
|
||||
posy: 206,
|
||||
width: 92,
|
||||
);
|
||||
|
||||
$pdf->page->addContent($bodyFont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<div style="font-size:10pt; line-height:1.25; color:rgb(22,37,61);">This QR code points to the official TCPDF project page:</div>',
|
||||
posx: 18,
|
||||
posy: 216,
|
||||
width: 118,
|
||||
);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<div style="font-size:10pt; color:rgb(22,37,61);"><a href="https://tcpdf.org">https://tcpdf.org</a></div>',
|
||||
posx: 18,
|
||||
posy: 228,
|
||||
width: 118,
|
||||
);
|
||||
|
||||
$pdf->page->addContent($pdf->getBarcode(
|
||||
type: 'QRCODE,H',
|
||||
code: 'https://tcpdf.org',
|
||||
posx: 145,
|
||||
posy: 206,
|
||||
width: 45,
|
||||
height: 45,
|
||||
padding: [0, 0, 0, 0],
|
||||
style: $barcodeStyle,
|
||||
));
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E001_invoice.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfa3,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 001');
|
||||
$pdf->setTitle('Example Invoice Factur-X 1.07 / ZUGFeRD 2.3');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf invoice Factur-X ZUGFeRD e-invoice XML');
|
||||
$pdf->setPDFFilename('001_invoice.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
// ----------
|
||||
|
||||
// Factur-X 1.07 / ZUGFeRD 2.3
|
||||
|
||||
$pageF01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Factur', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: '');
|
||||
|
||||
$pdf->page->addContent($bfont1['out']);
|
||||
|
||||
$invoiceHTML = '
|
||||
<h2 style="color:#003366;">INVOICE EXAMPLE</h2>
|
||||
<table border="0" cellspacing="0" cellpadding="2" style="width:100%;">
|
||||
<tr>
|
||||
<td style="width:50%; vertical-align:top;">
|
||||
<b>Seller</b><br/>
|
||||
ELEKTRON Industrieservice GmbH<br/>
|
||||
Geschäftsführer Egon Schrempp Amtsgericht Stuttgart HRB 1234<br/>
|
||||
Erfurter Strasse 13<br/>
|
||||
74465 Demoort, DE<br/>
|
||||
VAT: DE136695976
|
||||
</td>
|
||||
<td style="width:50%; vertical-align:top; text-align:right;">
|
||||
<b>Invoice No.:</b> 181301674<br/>
|
||||
<b>Invoice Date:</b> 15.11.2024<br/>
|
||||
<b>Delivery Date:</b> 01.11.2024<br/>
|
||||
<b>Order Ref.:</b> per Mail vom 01.09.2024<br/>
|
||||
<b>Project:</b> 13130162
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<b>Bill To:</b><br/>
|
||||
ConsultingService GmbH<br/>
|
||||
Attn: Liselotte Müller-Lüdenscheidt<br/>
|
||||
Musterstr. 18<br/>
|
||||
76138 Karlsruhe, DE<br/>
|
||||
<br/>
|
||||
<table border="1" cellspacing="0" cellpadding="3" style="width:100%; text-align:right;">
|
||||
<tr style="background-color:#003366; color:#ffffff;">
|
||||
<th style="text-align:left; width:8%;">Pos.</th>
|
||||
<th style="text-align:left; width:40%;">Description</th>
|
||||
<th style="width:12%;">Qty</th>
|
||||
<th style="width:10%;">Unit</th>
|
||||
<th style="width:15%;">Unit Price</th>
|
||||
<th style="width:15%;">Amount</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left;">01</td>
|
||||
<td style="text-align:left;">TGA Obermonteur/Monteur<br/><i>Beamermontage</i></td>
|
||||
<td>3</td>
|
||||
<td>HUR</td>
|
||||
<td>43.20</td>
|
||||
<td>129.60</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left;">02</td>
|
||||
<td style="text-align:left;">Beamer-Deckenhalterung<br/><i>Außerhalb Angebot</i></td>
|
||||
<td>1</td>
|
||||
<td>H87</td>
|
||||
<td>122.50</td>
|
||||
<td>122.50</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<table border="0" cellspacing="0" cellpadding="2" style="width:100%;">
|
||||
<tr>
|
||||
<td style="width:60%;"></td>
|
||||
<td style="width:40%;">
|
||||
<table border="1" cellspacing="0" cellpadding="3" style="width:100%; text-align:right;">
|
||||
<tr><td style="text-align:left;">Net Total</td><td>EUR 252.10</td></tr>
|
||||
<tr><td style="text-align:left;">VAT 19%</td><td>EUR 47.90</td></tr>
|
||||
<tr><td style="text-align:left;"><b>Grand Total</b></td><td><b>EUR 300.00</b></td></tr>
|
||||
<tr><td style="text-align:left;">Prepaid</td><td>EUR 0.00</td></tr>
|
||||
<tr><td style="text-align:left;"><b>Due Amount</b></td><td><b>EUR 300.00</b></td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<b>Payment Terms:</b> Zahlbar sofort rein netto<br/>
|
||||
<b>Bank:</b> IBAN DE91100000000123456789<br/>
|
||||
<b>Payment Reference:</b> Rechnung 181301674<br/>
|
||||
<br/>
|
||||
<i>Factur-X 1.07 / ZUGFeRD 2.3 — embedded XML attachment: factur-x.xml</i>
|
||||
';
|
||||
|
||||
$pdf->page->addContent($pdf->getHTMLCell($invoiceHTML, 15, 15, 180));
|
||||
|
||||
$invoiceXML = <<<XML
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:BusinessProcessSpecifiedDocumentContextParameter>
|
||||
<ram:ID>Baurechnung</ram:ID>
|
||||
</ram:BusinessProcessSpecifiedDocumentContextParameter>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>181301674</ram:ID>
|
||||
<ram:TypeCode>204</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20241115</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Rapport-Nr.: 42389 vom 01.11.2024
|
||||
Im 2. OG BT1 Besprechungsraum eine Beamerhalterung an die Decke montiert. Dafür eine Deckenplatte ausgesägt. Beamerhalterung zur Montage auseinander gebaut. Ein Stromkabel für den Beamer, ein HDMI Kabel und ein VGA Kabel durch die Halterung gezogen. Beamerhalterung wieder zusammengebaut und Beamer montiert. Beamer verkabelt und ausgerichtet. Decke geschlossen.</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>01</ram:LineID>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>01 Beamermontage
|
||||
Für die doppelte Verlegung, falls erforderlich.</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>TGA Obermonteur/Monteur</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>43.2</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>43.2</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="HUR">3</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>129.6</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>02</ram:LineID>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>02 Außerhalb Angebot</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Beamer-Deckenhalterung</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>122.5</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>122.5</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">1</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>122.5</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:BuyerReference>Liselotte Müller-Lüdenscheidt</ram:BuyerReference>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:ID>549910</ram:ID>
|
||||
<ram:Name>ELEKTRON Industrieservice GmbH</ram:Name>
|
||||
<ram:Description>Geschäftsführer Egon Schrempp Amtsgericht Stuttgart HRB 1234</ram:Description>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>74465</ram:PostcodeCode>
|
||||
<ram:LineOne>Erfurter Strasse 13</ram:LineOne>
|
||||
<ram:CityName>Demoort</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE136695976</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:ID>16259</ram:ID>
|
||||
<ram:Name>ConsultingService GmbH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>76138</ram:PostcodeCode>
|
||||
<ram:LineOne>Musterstr. 18</ram:LineOne>
|
||||
<ram:CityName>Karlsruhe</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:BuyerTradeParty>
|
||||
<ram:SellerOrderReferencedDocument>
|
||||
<ram:IssuerAssignedID>per Mail vom 01.09.2024</ram:IssuerAssignedID>
|
||||
</ram:SellerOrderReferencedDocument>
|
||||
<ram:AdditionalReferencedDocument>
|
||||
<ram:IssuerAssignedID>13130162</ram:IssuerAssignedID>
|
||||
<ram:URIID>#ef=Aufmass.png</ram:URIID>
|
||||
<ram:TypeCode>916</ram:TypeCode>
|
||||
</ram:AdditionalReferencedDocument>
|
||||
<ram:AdditionalReferencedDocument>
|
||||
<ram:IssuerAssignedID>42389</ram:IssuerAssignedID>
|
||||
<ram:URIID>#ef=ElektronRapport_neu-red.pdf</ram:URIID>
|
||||
<ram:TypeCode>916</ram:TypeCode>
|
||||
</ram:AdditionalReferencedDocument>
|
||||
<ram:SpecifiedProcuringProject>
|
||||
<ram:ID>13130162</ram:ID>
|
||||
<ram:Name>Projekt</ram:Name>
|
||||
</ram:SpecifiedProcuringProject>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20241101</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:PaymentReference>Rechnung 181301674</ram:PaymentReference>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:TypeCode>58</ram:TypeCode>
|
||||
<ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:IBANID>DE91100000000123456789</ram:IBANID>
|
||||
</ram:PayeePartyCreditorFinancialAccount>
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>47.9</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>252.1</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Zahlbar sofort rein netto</ram:Description>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>252.1</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount>0</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount>0</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>252.1</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">47.9</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>300</ram:GrandTotalAmount>
|
||||
<ram:TotalPrepaidAmount>0</ram:TotalPrepaidAmount>
|
||||
<ram:DuePayableAmount>300</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:ReceivableSpecifiedTradeAccountingAccount>
|
||||
<ram:ID>420</ram:ID>
|
||||
</ram:ReceivableSpecifiedTradeAccountingAccount>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
XML;
|
||||
|
||||
// Factur-X/ZUGFeRD requires the XML to be embedded as text/xml with the
|
||||
// AFRelationship set to "Alternative" and the exact file name "factur-x.xml".
|
||||
$pdf->addContentAsEmbeddedFile(
|
||||
file: 'factur-x.xml',
|
||||
content: $invoiceXML,
|
||||
mime: 'text/xml',
|
||||
afrel: \Com\Tecnick\Pdf\AFRelationship::Alternative,
|
||||
desc: 'Factur-X/ZUGFeRD electronic invoice',
|
||||
);
|
||||
|
||||
$pdf->setCustomXMP('x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas.rdf:Bag', '<rdf:li rdf:parseType="Resource">
|
||||
<pdfaSchema:schema>Factur-X PDFA Extension Schema</pdfaSchema:schema>
|
||||
<pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>
|
||||
<pdfaSchema:prefix>fx</pdfaSchema:prefix>
|
||||
<pdfaSchema:property>
|
||||
<rdf:Seq>
|
||||
<rdf:li rdf:parseType="Resource">
|
||||
<pdfaProperty:name>DocumentFileName</pdfaProperty:name>
|
||||
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
||||
<pdfaProperty:category>external</pdfaProperty:category>
|
||||
<pdfaProperty:description>The name of the embedded XML document</pdfaProperty:description>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType="Resource">
|
||||
<pdfaProperty:name>DocumentType</pdfaProperty:name>
|
||||
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
||||
<pdfaProperty:category>external</pdfaProperty:category>
|
||||
<pdfaProperty:description>The type of the hybrid document in capital letters, e.g. INVOICE or ORDER</pdfaProperty:description>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType="Resource">
|
||||
<pdfaProperty:name>Version</pdfaProperty:name>
|
||||
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
||||
<pdfaProperty:category>external</pdfaProperty:category>
|
||||
<pdfaProperty:description>The actual version of the standard applying to the embedded XML document</pdfaProperty:description>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType="Resource">
|
||||
<pdfaProperty:name>ConformanceLevel</pdfaProperty:name>
|
||||
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
||||
<pdfaProperty:category>external</pdfaProperty:category>
|
||||
<pdfaProperty:description>The conformance level of the embedded XML document</pdfaProperty:description>
|
||||
</rdf:li>
|
||||
</rdf:Seq>
|
||||
</pdfaSchema:property>
|
||||
</rdf:li>');
|
||||
|
||||
$pdf->setCustomXMP('x:xmpmeta.rdf:RDF', '<rdf:Description xmlns:fx="urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#" rdf:about="">
|
||||
<fx:DocumentType>INVOICE</fx:DocumentType>
|
||||
<fx:DocumentFileName>factur-x.xml</fx:DocumentFileName>
|
||||
<fx:Version>1.0</fx:Version>
|
||||
<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>
|
||||
</rdf:Description>');
|
||||
|
||||
// =============================================================
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E002_font_dump.php
|
||||
*
|
||||
* @since 2026-04-19
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 002');
|
||||
$pdf->setTitle('Font Dump and Glyph Coverage');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf fonts glyphs unicode dump metrics');
|
||||
$pdf->setPDFFilename('002_font_dump.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$titlefont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 16);
|
||||
|
||||
// core font families and styles
|
||||
$corefonts = [
|
||||
['family' => 'courier', 'style' => ''],
|
||||
['family' => 'courier', 'style' => 'B'],
|
||||
['family' => 'courier', 'style' => 'I'],
|
||||
['family' => 'courier', 'style' => 'BI'],
|
||||
['family' => 'helvetica', 'style' => ''],
|
||||
['family' => 'helvetica', 'style' => 'B'],
|
||||
['family' => 'helvetica', 'style' => 'I'],
|
||||
['family' => 'helvetica', 'style' => 'BI'],
|
||||
['family' => 'times', 'style' => ''],
|
||||
['family' => 'times', 'style' => 'B'],
|
||||
['family' => 'times', 'style' => 'I'],
|
||||
['family' => 'times', 'style' => 'BI'],
|
||||
['family' => 'symbol', 'style' => ''],
|
||||
['family' => 'zapfdingbats', 'style' => ''],
|
||||
];
|
||||
|
||||
foreach ($corefonts as $fontcfg) {
|
||||
$family = $fontcfg['family'];
|
||||
$style = $fontcfg['style'];
|
||||
$fontname = $family . ($style !== '' ? ' ' . $style : '');
|
||||
|
||||
$page = $pdf->addPage();
|
||||
$pdf->setBookmark(
|
||||
name: 'Font: ' . $fontname,
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: '',
|
||||
);
|
||||
|
||||
// title
|
||||
$pdf->page->addContent($titlefont['out']);
|
||||
$title = $pdf->getTextCell(
|
||||
'FONT: ' . $fontname,
|
||||
15,
|
||||
15,
|
||||
180,
|
||||
10,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
);
|
||||
$pdf->page->addContent($title);
|
||||
|
||||
// glyph table font
|
||||
$charfont = $pdf->font->insert($pdf->pon, $family, $style, 16);
|
||||
$pdf->page->addContent($charfont['out']);
|
||||
|
||||
// render character table (0-255) as a 16x16 grid
|
||||
for ($i = 0; $i < 256; ++$i) {
|
||||
$col = $i % 16;
|
||||
$row = (int) ($i / 16);
|
||||
$posx = 15 + ($col * 11.25);
|
||||
$posy = 30 + ($row * 11.25);
|
||||
|
||||
$txt = $pdf->uniconv->chr($i);
|
||||
$cell = $pdf->getTextCell(
|
||||
$txt,
|
||||
$posx,
|
||||
$posy,
|
||||
11.25,
|
||||
11.25,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
);
|
||||
$pdf->page->addContent($cell);
|
||||
}
|
||||
|
||||
$pangram = $pdf->getTextCell(
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
15,
|
||||
220,
|
||||
180,
|
||||
8,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
);
|
||||
$pdf->page->addContent($pangram);
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E003_persian_arabic.php
|
||||
*
|
||||
* @since 2026-04-19
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: false,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 003');
|
||||
$pdf->setTitle('Persian and Arabic RTL Text Rendering');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf persian arabic rtl bidi unicode shaping');
|
||||
$pdf->setPDFFilename('003_persian_arabic.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent(false);
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'dejavusans', '', 12);
|
||||
|
||||
// ----------
|
||||
|
||||
$txtEngPersian = 'PERSIAN: "The process of printing and correctly displaying Persian texts in digital systems requires full support for the Unicode standard and right-to-left layout. In this test text, all letters of the Persian alphabet, including specific letters like "Pe", "Che", "Zhe", and "Gaf", are included to verify their correct connectivity. Additionally, the use of Persian numbers (1234567890) and punctuation marks like commas (,) and semicolons (;) is essential for accurately measuring the alignment of lines and margins on multi-line pages."';
|
||||
|
||||
$txtPersian = 'فرآیند چاپ و نمایش صحیح متون فارسی در سیستمهای دیجیتال نیازمند پشتیبانی کامل از استاندارد یونیکد و چیدمان راستبهچپ است. در این متن آزمایشی، تمامی حروف الفبای فارسی از جمله حروف خاص مانند «پ»، «چ»، «ژ» و «گ» گنجانده شدهاند تا صحت اتصال آنها بررسی شود. همچنین استفاده از اعداد فارسی (۱۲۳۴۵۶۷۸۹۰) و علائم نگارشی مانند ویرگول (،) و نقطهویرگول (؛) برای سنجش دقیق ترازبندی خطوط و حاشیههای صفحات چندخطی الزامی است.';
|
||||
|
||||
$htmlPersian = '<p style="direction:rtl;text-align:right;color:#003366;" lang="fa">فرآیند چاپ و نمایش صحیح متون فارسی در سیستمهای دیجیتال نیازمند پشتیبانی کامل از استاندارد یونیکد و چیدمان راستبهچپ است. در این متن آزمایشی، تمامی حروف الفبای فارسی از جمله حروف خاص مانند <span style="color:#660000;">«پ»، «چ»، «ژ» و «گ»</span> گنجانده شدهاند تا صحت اتصال آنها بررسی شود. همچنین استفاده از اعداد فارسی <span style="color:#006600;">(۱۲۳۴۵۶۷۸۹۰)</span> و علائم نگارشی مانند ویرگول (،) و نقطهویرگول (؛) برای سنجش دقیق ترازبندی خطوط و حاشیههای صفحات چندخطی الزامی است.</p>';
|
||||
|
||||
$txtEngArabic = 'ARABIC: "The process of printing and correctly displaying Arabic texts on digital screens requires full support for the Unicode system and right-to-left formatting. This test text contains various letters, including elongated letters and different Hamzas (أ، إ، آ، ء، ئ، ؤ), to ensure the accuracy of letter connectivity. The text also includes Arabic numerals (1234567890) and punctuation marks such as the comma (،) and semicolon (؛) to verify the integrity of line alignment and multi-page margins."';
|
||||
|
||||
$txtArabic = 'إن عملية طباعة النصوص العربية وعرضها بشكل صحيح على الشاشات الرقمية تتطلب دعماً كاملاً لنظام اليونيكود والتنسيق من اليمين إلى اليسار. يحتوي هذا النص التجريبي على حروف متنوعة تشمل الحروف الممدودة والهمزات المختلفة مثل (أ، إ، آ، ء، ئ، ؤ) لضمان دقة اتصال الحروف ببعضها. كما يتضمن النص الأرقام العربية (١٢٣٤٥٦٧٨٩٠) وعلامات الترقيم كالفاصلة (،) والفاصلة المنقوطة (؛) للتحقق من سلامة محاذاة الأسطر وهوامش الصفحات المتعددة.';
|
||||
|
||||
$htmlArabic = '<p style="direction:rtl;text-align:right;color:#003366;" lang="ar">إن عملية طباعة النصوص العربية وعرضها بشكل صحيح على الشاشات الرقمية تتطلب دعماً كاملاً لنظام اليونيكود والتنسيق من اليمين إلى اليسار. يحتوي هذا النص التجريبي على حروف متنوعة تشمل الحروف الممدودة والهمزات المختلفة مثل <span style="color:#660000;">(أ، إ، آ، ء، ئ، ؤ)</span> لضمان دقة اتصال الحروف ببعضها. كما يتضمن النص الأرقام العربية <span style="color:#006600;">(١٢٣٤٥٦٧٨٩٠)</span> وعلامات الترقيم كالفاصلة (،) والفاصلة المنقوطة (؛) للتحقق من سلامة محاذاة الأسطر وهوامش الصفحات المتعددة.</p>';
|
||||
|
||||
$txtEngHebrew = 'HEBREW: "The process of printing and correctly displaying text in Hebrew on digital systems requires full support for the Unicode standard and right-to-left formatting. In this experimental text, all letters of the alphabet are included, including the final letters (ך, ם, ן, ף, ץ) to verify their correct display. Furthermore, the text integrates numbers (1234567890) and various punctuation marks like a comma (,) and semicolon (;) in order to examine line alignment and page margins in long paragraphs."';
|
||||
|
||||
$txtHebrew = 'תהליך ההדפסה וההצגה התקינה של טקסט בעברית במערכות דיגיטליות דורש תמיכה מלאה בתקן יוניקוד ובתצורת כתיבה מימין לשמאל. בטקסט ניסיוני זה נכללו כל אותיות האלפבית, כולל האותיות הסופיות (ך, ם, ן, ף, ץ) כדי לבדוק את תקינות התצוגה שלהן. כמו כן, הטקסט משלב מספרים (1234567890) וסימני פיסוק שונים כמו פסיק (,) ונקודה ופסיק (;) על מנת לבחון את יישור השורות ואת שולי העמודים בפסקאות ארוכות.';
|
||||
|
||||
$htmlHebrew = '<p style="direction:rtl;text-align:right;color:#003366;" lang="he">תהליך ההדפסה וההצגה התקינה של טקסט בעברית במערכות דיגיטליות דורש תמיכה מלאה בתקן יוניקוד ובתצורת כתיבה מימין לשמאל. בטקסט ניסיוני זה נכללו כל אותיות האלפבית, כולל האותיות הסופיות <span style="color:#660000;">(ך, ם, ן, ף, ץ)</span> כדי לבדוק את תקינות התצוגה שלהן. כמו כן, הטקסט משלב מספרים <span style="color:#006600;">(1234567890)</span> וסימני פיסוק שונים כמו פסיק (,) ונקודה ופסיק (;) על מנת לבחון את יישור השורות ואת שולי העמודים בפסקאות ארוכות.</p>';
|
||||
|
||||
// ----------
|
||||
|
||||
$psx = 15;
|
||||
$lnw = 180;
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<h1>RTL (Right-To-Left) Examples</h1><h2>1. getTextCell()</h2>',
|
||||
posx: $psx,
|
||||
posy: 15,
|
||||
width: $lnw,
|
||||
);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $txtEngPersian,
|
||||
posx: $psx,
|
||||
posy: 40,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->setRTL(true);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $txtPersian,
|
||||
posx: $psx,
|
||||
posy: 80,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
));
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $txtEngArabic,
|
||||
posx: $psx,
|
||||
posy: 120,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->setRTL(true);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $txtArabic,
|
||||
posx: $psx,
|
||||
posy: 160,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
));
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $txtEngHebrew,
|
||||
posx: $psx,
|
||||
posy: 200,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->setRTL(true);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $txtHebrew,
|
||||
posx: $psx,
|
||||
posy: 240,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
));
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(html: '<h2>2. addTextCell()</h2>', posx: $psx, posy: 15, width: $lnw);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addTextCell(
|
||||
txt: $txtEngPersian,
|
||||
posx: $psx,
|
||||
posy: 40,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->setRTL(true);
|
||||
$pdf->addTextCell(
|
||||
txt: $txtPersian,
|
||||
posx: $psx,
|
||||
posy: 80,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addTextCell(
|
||||
txt: $txtEngArabic,
|
||||
posx: $psx,
|
||||
posy: 120,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->setRTL(true);
|
||||
$pdf->addTextCell(
|
||||
txt: $txtArabic,
|
||||
posx: $psx,
|
||||
posy: 160,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addTextCell(
|
||||
txt: $txtEngHebrew,
|
||||
posx: $psx,
|
||||
posy: 200,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->setRTL(true);
|
||||
$pdf->addTextCell(
|
||||
txt: $txtHebrew,
|
||||
posx: $psx,
|
||||
posy: 240,
|
||||
width: $lnw,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(html: '<h2>3. getHTMLCell() - simple text</h2>', posx: $psx, posy: 15, width: $lnw);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtEngPersian, posx: $psx, posy: 40, width: $lnw));
|
||||
$pdf->setRTL(true);
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtPersian, posx: $psx, posy: 80, width: $lnw));
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtEngArabic, posx: $psx, posy: 120, width: $lnw));
|
||||
$pdf->setRTL(true);
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtArabic, posx: $psx, posy: 160, width: $lnw));
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtEngHebrew, posx: $psx, posy: 200, width: $lnw));
|
||||
$pdf->setRTL(true);
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtHebrew, posx: $psx, posy: 240, width: $lnw));
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(html: '<h2>4. addtHTMLCell() - simple text</h2>', posx: $psx, posy: 15, width: $lnw);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(html: $txtEngPersian, posx: $psx, posy: 40, width: $lnw);
|
||||
$pdf->setRTL(true);
|
||||
$pdf->addHTMLCell(html: $txtPersian, posx: $psx, posy: 80, width: $lnw);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(html: $txtEngArabic, posx: $psx, posy: 120, width: $lnw);
|
||||
$pdf->setRTL(true);
|
||||
$pdf->addHTMLCell(html: $txtArabic, posx: $psx, posy: 160, width: $lnw);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(html: $txtEngHebrew, posx: $psx, posy: 200, width: $lnw);
|
||||
$pdf->setRTL(true);
|
||||
$pdf->addHTMLCell(html: $txtHebrew, posx: $psx, posy: 240, width: $lnw);
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->setRTL(false);
|
||||
$pdf->addHTMLCell(html: '<h2>5. getHTMLCell() - HTML fragments</h2>', posx: $psx, posy: 15, width: $lnw);
|
||||
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtEngPersian, posx: $psx, posy: 40, width: $lnw));
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $htmlPersian, posx: $psx, posy: 80, width: $lnw));
|
||||
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtEngArabic, posx: $psx, posy: 120, width: $lnw));
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $htmlArabic, posx: $psx, posy: 160, width: $lnw));
|
||||
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $txtEngHebrew, posx: $psx, posy: 200, width: $lnw));
|
||||
$pdf->page->addContent($pdf->getHTMLCell(html: $htmlHebrew, posx: $psx, posy: 240, width: $lnw));
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->addHTMLCell(html: '<h2>6. addtHTMLCell() - HTML fragments</h2>', posx: $psx, posy: 15, width: $lnw);
|
||||
|
||||
$pdf->addHTMLCell(html: $txtEngPersian, posx: $psx, posy: 40, width: $lnw);
|
||||
$pdf->addHTMLCell(html: $htmlPersian, posx: $psx, posy: 80, width: $lnw);
|
||||
|
||||
$pdf->addHTMLCell(html: $txtEngArabic, posx: $psx, posy: 120, width: $lnw);
|
||||
$pdf->addHTMLCell(html: $htmlArabic, posx: $psx, posy: 160, width: $lnw);
|
||||
|
||||
$pdf->addHTMLCell(html: $txtEngHebrew, posx: $psx, posy: 200, width: $lnw);
|
||||
$pdf->addHTMLCell(html: $htmlHebrew, posx: $psx, posy: 240, width: $lnw);
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->addHTMLCell(html: '<h2>7. addtHTMLCell() - HTML fragments with images</h2>', posx: $psx, posy: 15, width: $lnw);
|
||||
|
||||
$rtlHtmlWithImage = '<p style="direction:rtl;text-align:right;color:#003366;" lang="fa"><img src="images/tcpdf_logo.jpg" alt="TCPDF logo" height="3mm" border="0" /> فرآیند چاپ و نمایش صحیح متون فارسی در سیستمهای دیجیتال نیازمند پشتیبانی کامل از استاندارد یونیکد و چیدمان راستبهچپ است. در این متن آزمایشی، تمامی حروف الفبای فارسی از جمله حروف خاص مانند <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" height="3mm" border="0" /> <span style="color:#660000;">«پ»، «چ»، «ژ» و «گ»</span> گنجانده شدهاند تا صحت اتصال آنها بررسی شود. همچنین استفاده از اعداد فارسی <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" height="3mm" border="0" /> <span style="color:#006600;">(۱۲۳۴۵۶۷۸۹۰)</span> و علائم نگارشی مانند ویرگول (،) و نقطهویرگول (؛) برای سنجش دقیق ترازبندی خطوط و حاشیههای صفحات چندخطی الزامی است. <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" height="3mm" border="0" /></p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $rtlHtmlWithImage, posx: $psx, posy: 40, width: $lnw);
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->addHTMLCell(
|
||||
html: '<h2>8. addHTMLCell() - RTL paragraph spanning a page break</h2>',
|
||||
posx: $psx,
|
||||
posy: 15,
|
||||
width: $lnw,
|
||||
);
|
||||
|
||||
// A long multi-fragment RTL paragraph placed low on the page so that it overflows
|
||||
// the page bottom and must continue on the next page. This exercises Stage 2e (RTL
|
||||
// region/page continuation): the inter-fragment engine must flow the remaining
|
||||
// right-to-left lines into the next page, keeping them top-down and right-to-left,
|
||||
// instead of falling back to the forward-cursor renderer. See
|
||||
// PLAN_RTL_HTML_FRAGMENTS.md increment 4.
|
||||
$arabicSpanCycle =
|
||||
$txtArabic
|
||||
. ' <span style="color:#660000;">'
|
||||
. $txtArabic
|
||||
. '</span> '
|
||||
. $txtArabic
|
||||
. ' <span style="color:#006600;">'
|
||||
. $txtArabic
|
||||
. '</span> ';
|
||||
$htmlArabicLong =
|
||||
'<p style="direction:rtl;text-align:right;color:#003366;" lang="ar">' . \str_repeat($arabicSpanCycle, 2) . '</p>';
|
||||
$pdf->addHTMLCell(html: $htmlArabicLong, posx: $psx, posy: 180, width: $lnw);
|
||||
|
||||
// =============================================================
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E004_page_formats.php
|
||||
*
|
||||
* @since 2026-04-19
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 004');
|
||||
$pdf->setTitle('Page Formats and Orientation');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf page formats orientation A4 Letter custom size');
|
||||
$pdf->setPDFFilename('004_page_formats.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent(false);
|
||||
|
||||
// ----------
|
||||
// Get all page formats from the Format class
|
||||
$formats = \Com\Tecnick\Pdf\Page\Format::FORMAT;
|
||||
|
||||
// Insert monospace font
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'courier', '', 8);
|
||||
|
||||
// Conversion factor: points to mm and inches
|
||||
$mmRatio = \Com\Tecnick\Pdf\Page\Format::UNITRATIO['mm'];
|
||||
$inRatio = \Com\Tecnick\Pdf\Page\Format::UNITRATIO['in'];
|
||||
|
||||
// Loop through all formats
|
||||
foreach ($formats as $formatName => $dimensions) {
|
||||
// Add a new page using the named format.
|
||||
$page = $pdf->addPage(['format' => $formatName]);
|
||||
|
||||
// Get dimensions.
|
||||
$widthPt = $dimensions[0];
|
||||
$heightPt = $dimensions[1];
|
||||
|
||||
// Calculate dimensions in mm and inches.
|
||||
$widthMm = $widthPt / $mmRatio;
|
||||
$heightMm = $heightPt / $mmRatio;
|
||||
$widthIn = $widthPt / $inRatio;
|
||||
$heightIn = $heightPt / $inRatio;
|
||||
|
||||
// Print multiline text at top-left corner.
|
||||
$x = 2;
|
||||
$y = 2;
|
||||
$w = 50;
|
||||
|
||||
// Define multiline HTML text to display.
|
||||
$html = '<h2>' . $formatName . '</h2>';
|
||||
|
||||
if ($page['width'] > ($w + (2 * $x))) {
|
||||
$html .= '<table border="1" cellspacing="0" cellpadding="2" style="text-align:right">
|
||||
<tr><th>unit</th><th>width</th><th>height</th></tr>';
|
||||
$html .= \sprintf('<tr><td>mm</td><td>%.3f</td><td>%.3f</td></tr>', $widthMm, $heightMm);
|
||||
$html .= \sprintf('<tr><td>in</td><td>%.3f</td><td>%.3f</td></tr>', $widthIn, $heightIn);
|
||||
$html .= \sprintf('<tr><td>pt</td><td>%.3f</td><td>%.3f</td></tr>', $widthPt, $heightPt);
|
||||
$html .= '</table>';
|
||||
}
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->page->addContent($pdf->getHTMLCell($html, $x, $y, $w));
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E005_header_footer.php
|
||||
*
|
||||
* @since 2026-04-19
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// ----------
|
||||
|
||||
/**
|
||||
* Custom PDF class with a repeating page header and footer.
|
||||
*
|
||||
* Extends Tcpdf and overrides defaultPageContent() so that every
|
||||
* new page automatically receives a branded header and a numbered footer.
|
||||
* The mechanism is activated by calling enableDefaultPageContent(true).
|
||||
*/
|
||||
class PdfWithHeaderFooter extends \Com\Tecnick\Pdf\Tcpdf
|
||||
{
|
||||
/** Horizontal margin used by the header and footer bands (mm). */
|
||||
private const HF_MARGIN = 10.0;
|
||||
|
||||
/** Height of the header band (mm). */
|
||||
private const HEADER_H = 12.0;
|
||||
|
||||
/** Height of the footer band (mm). */
|
||||
private const FOOTER_H = 10.0;
|
||||
|
||||
/** Document title shown left-aligned in the header. */
|
||||
private string $headerTitle = '';
|
||||
|
||||
/** Subtitle / date shown right-aligned in the header. */
|
||||
private string $headerSubtitle = '';
|
||||
|
||||
/**
|
||||
* Set the text displayed in the page header.
|
||||
*
|
||||
* @param string $title Left-aligned title.
|
||||
* @param string $subtitle Right-aligned subtitle (e.g. date or company name).
|
||||
*/
|
||||
public function setHeaderText(string $title, string $subtitle): void
|
||||
{
|
||||
$this->headerTitle = $title;
|
||||
$this->headerSubtitle = $subtitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the repeating header and footer for every page.
|
||||
*
|
||||
* This method is called automatically by setPageContext() whenever a new
|
||||
* page is added, provided enableDefaultPageContent(true) has been called.
|
||||
*
|
||||
* @param int $pid Page index (0-based).
|
||||
*
|
||||
* @return string Raw PDF stream prepended to the page content.
|
||||
*/
|
||||
public function defaultPageContent(int $pid = -1): string
|
||||
{
|
||||
if ($pid < 0) {
|
||||
$pid = $this->page->getPageId();
|
||||
}
|
||||
|
||||
// Insert the default font once and cache it for subsequent pages.
|
||||
if ($this->defaultfont === null) {
|
||||
$this->defaultfont = $this->font->insert($this->pon, 'helvetica', '', 9);
|
||||
}
|
||||
|
||||
$page = $this->page->getPage($pid);
|
||||
$pw = $page['width'];
|
||||
$ph = $page['height'];
|
||||
|
||||
$lm = self::HF_MARGIN; // left margin x
|
||||
$rm = $pw - self::HF_MARGIN; // right margin x
|
||||
$tw = $pw - (2 * self::HF_MARGIN); // usable band width
|
||||
|
||||
$lineStyle = [
|
||||
'lineWidth' => 0.25,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#555555',
|
||||
];
|
||||
|
||||
$out = '';
|
||||
|
||||
// ---- HEADER ------------------------------------------------
|
||||
|
||||
$headerY = self::HF_MARGIN;
|
||||
$headerOut = $this->graph->getStartTransform();
|
||||
$headerOut .= $this->defaultfont['out'];
|
||||
|
||||
// Title – left-aligned, bold
|
||||
if ($this->headerTitle !== '') {
|
||||
$bfontBold = $this->font->insert($this->pon, 'helvetica', 'B', 10);
|
||||
$headerOut .= $bfontBold['out'];
|
||||
$headerOut .= $this->color->getPdfColor('#1a3a6b');
|
||||
$headerOut .= $this->getTextCell(
|
||||
txt: $this->headerTitle,
|
||||
posx: $lm,
|
||||
posy: $headerY,
|
||||
width: $tw * 0.65,
|
||||
height: self::HEADER_H,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$headerOut .= $this->defaultfont['out'];
|
||||
}
|
||||
|
||||
// Subtitle – right-aligned
|
||||
if ($this->headerSubtitle !== '') {
|
||||
$headerOut .= $this->color->getPdfColor('#555555');
|
||||
$headerOut .= $this->getTextCell(
|
||||
txt: $this->headerSubtitle,
|
||||
posx: $lm + ($tw * 0.65),
|
||||
posy: $headerY,
|
||||
width: $tw * 0.35,
|
||||
height: self::HEADER_H,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
);
|
||||
}
|
||||
|
||||
// Separator line below the header
|
||||
$headerLineY = $headerY + self::HEADER_H;
|
||||
$headerOut .= $this->graph->getLine($lm, $headerLineY, $rm, $headerLineY, $lineStyle);
|
||||
$headerOut .= $this->graph->getStopTransform();
|
||||
|
||||
$out .= $this->beginArtifact('Pagination', 'Header');
|
||||
$out .= $headerOut;
|
||||
$out .= $this->endArtifact();
|
||||
|
||||
// ---- FOOTER ------------------------------------------------
|
||||
|
||||
$footerLineY = $ph - self::HF_MARGIN - self::FOOTER_H;
|
||||
$footerOut = $this->graph->getStartTransform();
|
||||
$footerOut .= $this->defaultfont['out'];
|
||||
|
||||
// Separator line above the footer
|
||||
$footerOut .= $this->graph->getLine($lm, $footerLineY, $rm, $footerLineY, $lineStyle);
|
||||
|
||||
// Page number – centred
|
||||
$footerOut .= $this->color->getPdfColor('#555555');
|
||||
$footerOut .= $this->getTextCell(
|
||||
txt: 'Page ' . ($pid + 1),
|
||||
posx: $lm,
|
||||
posy: $footerLineY,
|
||||
width: $tw,
|
||||
height: self::FOOTER_H,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
);
|
||||
$footerOut .= $this->graph->getStopTransform();
|
||||
|
||||
$out .= $this->beginArtifact('Pagination', 'Footer');
|
||||
$out .= $footerOut;
|
||||
$out .= $this->endArtifact();
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
// main PDF object using the custom subclass
|
||||
$pdf = new PdfWithHeaderFooter(
|
||||
'mm', // string $unit = 'mm',
|
||||
true, // bool $isunicode = true,
|
||||
false, // bool $subsetfont = false,
|
||||
true, // bool $compress = true,
|
||||
'pdfua1', // string $mode = 'pdfua1',
|
||||
null, // ?ObjEncrypt $objEncrypt = null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 005');
|
||||
$pdf->setTitle('Header & Footer Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example header footer');
|
||||
$pdf->setPDFFilename('005_header_footer.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->setLanguageArray(['a_meta_language' => 'en-US']);
|
||||
|
||||
// Set the text that will appear in the header on every page.
|
||||
$pdf->setHeaderText('My Document Title', \date('Y-m-d'));
|
||||
|
||||
// Enable automatic header/footer: calls defaultPageContent() for every new page.
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 13);
|
||||
|
||||
// ----------
|
||||
// Add first page
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Page 1', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'blue');
|
||||
|
||||
// Page content starts below the header band (HF_MARGIN + HEADER_H + separator ≈ 25 mm).
|
||||
$contentY = 28.0;
|
||||
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
|
||||
$title1 = $pdf->getTextCell(
|
||||
txt: 'Page 1 — Custom Repeating Header & Footer',
|
||||
posx: 10,
|
||||
posy: $contentY,
|
||||
width: 190,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($title1);
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$body1 = 'This is the first page of a document that demonstrates how to add a custom page header and footer that automatically repeats on every new page using tc-lib-pdf.
|
||||
|
||||
The header displays the document title (left) and the date (right), separated from the page content by a thin horizontal rule. The footer shows the page number centred at the bottom, also separated by a horizontal rule.
|
||||
|
||||
This is achieved by subclassing \Com\Tecnick\Pdf\Tcpdf and overriding the public defaultPageContent() method, then activating the mechanism once with enableDefaultPageContent(true) before adding any pages.
|
||||
|
||||
Because setPageContext() calls defaultPageContent() automatically every time addPage() is used, the header and footer appear on every page without any additional code in the page-building section.';
|
||||
|
||||
$txt1 = $pdf->getTextCell(
|
||||
txt: $body1,
|
||||
posx: 10,
|
||||
posy: $contentY + 10,
|
||||
width: 190,
|
||||
height: 0,
|
||||
offset: 15,
|
||||
linespace: 2,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->page->addContent($txt1);
|
||||
|
||||
// ----------
|
||||
// Add second page
|
||||
|
||||
$page02 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Page 2', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'green');
|
||||
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
|
||||
$title2 = $pdf->getTextCell(
|
||||
txt: 'Page 2 — Continued Content',
|
||||
posx: 10,
|
||||
posy: $contentY,
|
||||
width: 190,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($title2);
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$body2 = 'This is the second page. The header and footer are present here too without any manual intervention — the overridden defaultPageContent() method takes care of them automatically.
|
||||
|
||||
Any further pages added with addPage() would also receive the same header and footer, making the approach suitable for multi-page reports, invoices, or any document type that requires consistent page decoration.';
|
||||
|
||||
$txt2 = $pdf->getTextCell(
|
||||
txt: $body2,
|
||||
posx: 10,
|
||||
posy: $contentY + 10,
|
||||
width: 190,
|
||||
height: 0,
|
||||
offset: 15,
|
||||
linespace: 2,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->page->addContent($txt2);
|
||||
|
||||
// ----------
|
||||
// Output the PDF
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E006_minimal.php
|
||||
*
|
||||
* @since 2026-04-19
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 006');
|
||||
$pdf->setTitle('Minimal Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf minimal hello world basic');
|
||||
$pdf->setPDFFilename('006_minimal.pdf');
|
||||
|
||||
// Insert font
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// Add first page
|
||||
$page = $pdf->addPage();
|
||||
|
||||
// Add font to the page
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// some HTML content
|
||||
$html = '<h1>Hello, PDF!</h1><p>Generated with tc-lib-pdf.</p>';
|
||||
|
||||
// render the HTML content
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 15, width: 180);
|
||||
|
||||
// Get the PDF content
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Render the PDF content
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E007_signature_basic.php
|
||||
*
|
||||
* @since 2026-04-21
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 007');
|
||||
$pdf->setTitle('PAdES B-B Digital Signature Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example signature pades pades-b-b');
|
||||
$pdf->setPDFFilename('007_signature_basic.pdf');
|
||||
|
||||
// Insert font before adding the first page.
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
|
||||
// Add a page and a simple signed-content block.
|
||||
$page = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$text = 'This document is signed with a PAdES-BASELINE-B signature (/ETSI.CAdES.detached).';
|
||||
$textCell = $pdf->getTextCell(
|
||||
txt: $text,
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell);
|
||||
|
||||
$text2 = 'The CMS carries the ESS signing-certificate-v2 attribute required by ETSI EN 319 142-1.';
|
||||
$textCell2 = $pdf->getTextCell(
|
||||
txt: $text2,
|
||||
posx: 15,
|
||||
posy: 27,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell2);
|
||||
|
||||
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
|
||||
if ($certPath === false) {
|
||||
throw new \RuntimeException('Missing signing certificate: examples/data/cert/tcpdf.crt');
|
||||
}
|
||||
|
||||
$cert = 'file://' . $certPath;
|
||||
|
||||
// Preferred fluent API: $pdf->signature()->configure(...). The 'profile' option
|
||||
// selects the PAdES baseline level (legacy | pades-b-b | pades-b-t | pades-b-lt |
|
||||
// pades-b-lta); the pre-facade $pdf->setSignature([...]) method still works and
|
||||
// takes the same array. The signing process and this demo's limitations are
|
||||
// rendered into the document itself (see the explanatory block added below).
|
||||
$pdf->signature()->configure([
|
||||
'profile' => 'pades-b-b',
|
||||
'digest_algorithm' => 'sha256', // sha256 | sha384 | sha512
|
||||
'cert_type' => 2,
|
||||
'info' => [
|
||||
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
'Location' => 'Demo Office',
|
||||
'Name' => 'tc-lib-pdf',
|
||||
'Reason' => 'PAdES-BASELINE-B signature example',
|
||||
],
|
||||
'password' => '',
|
||||
'privkey' => $cert,
|
||||
'signcert' => $cert,
|
||||
]);
|
||||
|
||||
// Visible signature field plus one extra empty approval signature field.
|
||||
$pdf->signature()->appearance()->place(posx: 15, posy: 35, width: 75, height: 20, page: -1, name: 'PrimarySignature');
|
||||
|
||||
// Optional custom appearance stream for the signature widget (/AP /N).
|
||||
// Coordinate system starts from the lower-left corner of the widget rectangle.
|
||||
$sigW = 75.0;
|
||||
$sigH = 20.0;
|
||||
$sigTopY = $page['height'] - $sigH;
|
||||
|
||||
// styles controls cell fill/border; set font and text color explicitly for AP text.
|
||||
$sigAppearance = $bfont['out'];
|
||||
$sigAppearance .= $pdf->color->getPdfColor('rgb(15%,15%,15%)');
|
||||
$sigAppearance .= $pdf->getTextCell(
|
||||
txt: 'Digitally signed by tc-lib-pdf',
|
||||
posx: 0,
|
||||
posy: $sigTopY,
|
||||
width: $sigW,
|
||||
height: $sigH,
|
||||
offset: 2.5,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [
|
||||
'all' => [
|
||||
'fillColor' => 'rgb(92%,96%,100%)',
|
||||
'lineColor' => 'rgb(20%,32%,60%)',
|
||||
'lineWidth' => 1.2,
|
||||
],
|
||||
],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
);
|
||||
|
||||
$pdf->signature()->appearance()->stream(stream: $sigAppearance);
|
||||
|
||||
// Exposed object ID of the signature widget annotation.
|
||||
// This can be useful for low-level workflows or custom QA checks.
|
||||
$signatureWidgetObjId = $pdf->signature()->widgetObjectId();
|
||||
$text3 = 'Primary signature widget object ID: ' . $signatureWidgetObjId;
|
||||
$textCell3 = $pdf->getTextCell(
|
||||
txt: $text3,
|
||||
posx: 95,
|
||||
posy: 35,
|
||||
width: 100,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell3);
|
||||
|
||||
// A second, empty signature field. It is a valid unsigned placeholder (no CMS is
|
||||
// written to it) that a later party can sign in an approval workflow. Only the
|
||||
// PrimarySignature field above carries a signature in this example's output.
|
||||
$pdf->signature()->emptyField(posx: 15, posy: 60, width: 75, height: 20, page: -1, name: 'ApprovalSignature');
|
||||
|
||||
// Render the signing process and the demo's limitations into the document so the
|
||||
// output PDF is self-documenting (this text is page content, not part of the
|
||||
// signed appearance stream).
|
||||
$explainHtml = <<<HTML
|
||||
<h2 style="font-size:11pt;color:#1f2a33;">How this PAdES-BASELINE-B signature is produced</h2>
|
||||
<p style="font-size:9pt;color:#1f2a33;">The library reserves a <code>/Contents</code> placeholder inside a
|
||||
<code>/SubFilter /ETSI.CAdES.detached</code> signature field, hashes the document over the two
|
||||
<code>/ByteRange</code> spans that surround the placeholder, and embeds a detached CMS (PKCS#7). The
|
||||
CAdES SignerInfo carries the mandatory content-type and message-digest attributes plus the ESS
|
||||
signing-certificate-v2 attribute required by ETSI EN 319 142-1. Per the baseline the CMS signing-time
|
||||
attribute is intentionally omitted; the claimed time is carried by the <code>/M</code> dictionary entry
|
||||
instead. The produced CMS verifies cryptographically against the <code>/ByteRange</code> bytes.</p>
|
||||
<h2 style="font-size:11pt;color:#7a1f1f;">Limitations of this demo</h2>
|
||||
<ul style="font-size:9pt;color:#1f2a33;">
|
||||
<li>B-B has no timestamp, so the <code>/M</code> signing time is a self-asserted claim and is not
|
||||
cryptographically protected. Use <code>pades-b-t</code> (example E008) for a trusted signing time
|
||||
backed by an RFC 3161 TSA.</li>
|
||||
<li>The bundled certificate <code>examples/data/cert/tcpdf.crt</code> is self-signed. The CMS is
|
||||
cryptographically valid, but the signer identity does not chain to a trusted root, so viewers report
|
||||
the signature as valid with an unknown or untrusted signer. Sign with a CA-issued certificate for a
|
||||
trusted identity verdict.</li>
|
||||
</ul>
|
||||
HTML;
|
||||
$pdf->addHTMLCell(html: $explainHtml, posx: 15, posy: 85, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E008_signature_timestamp.php
|
||||
*
|
||||
* @since 2026-04-21
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 008');
|
||||
$pdf->setTitle('PAdES B-T Signature Timestamp Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example signature timestamp tsa pades pades-b-t');
|
||||
$pdf->setPDFFilename('008_signature_timestamp.pdf');
|
||||
|
||||
// Insert font before adding the first page.
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
|
||||
$page = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$text = 'This document is a PAdES-BASELINE-T signature: B-B plus an RFC 3161 signature timestamp.';
|
||||
$textCell = $pdf->getTextCell(
|
||||
txt: $text,
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell);
|
||||
|
||||
$text2 = 'Timestamping requires outbound HTTPS connectivity to the configured TSA endpoint.';
|
||||
$textCell2 = $pdf->getTextCell(
|
||||
txt: $text2,
|
||||
posx: 15,
|
||||
posy: 27,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell2);
|
||||
|
||||
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
|
||||
if ($certPath === false) {
|
||||
throw new \RuntimeException('Missing signing certificate: examples/data/cert/tcpdf.crt');
|
||||
}
|
||||
|
||||
$cert = 'file://' . $certPath;
|
||||
|
||||
// PAdES-BASELINE-T: configure() selects the profile, timestamp() adds the TSA;
|
||||
// both calls are chainable. The signing process and this demo's limitations are
|
||||
// rendered into the document itself (see the explanatory block added below).
|
||||
$pdf
|
||||
->signature()
|
||||
->configure([
|
||||
'profile' => 'pades-b-t',
|
||||
'digest_algorithm' => 'sha256',
|
||||
'cert_type' => 2,
|
||||
'info' => [
|
||||
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
'Location' => 'Demo Office',
|
||||
'Name' => 'tc-lib-pdf',
|
||||
'Reason' => 'PAdES-BASELINE-T timestamped signature example',
|
||||
],
|
||||
'password' => '',
|
||||
'privkey' => $cert,
|
||||
'signcert' => $cert,
|
||||
])
|
||||
->timestamp([
|
||||
'enabled' => true,
|
||||
// Public demo endpoint. For production use your trusted TSA service.
|
||||
'host' => 'https://freetsa.org/tsr',
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'cert' => '',
|
||||
'hash_algorithm' => 'sha256',
|
||||
'policy_oid' => '',
|
||||
'nonce_enabled' => true,
|
||||
'timeout' => 30,
|
||||
'verify_peer' => true,
|
||||
]);
|
||||
|
||||
$pdf
|
||||
->signature()
|
||||
->appearance()
|
||||
->place(posx: 15, posy: 35, width: 90, height: 20, page: -1, name: 'TimestampedSignature');
|
||||
|
||||
// Optional appearance stream to clearly indicate timestamped signature intent.
|
||||
$sigW = 90.0;
|
||||
$sigH = 20.0;
|
||||
$sigTopY = $page['height'] - $sigH;
|
||||
|
||||
$sigAppearance = $bfont['out'];
|
||||
$sigAppearance .= $pdf->color->getPdfColor('rgb(20%,20%,20%)');
|
||||
$sigAppearance .= $pdf->getTextCell(
|
||||
txt: 'PAdES B-T Timestamped Signature',
|
||||
posx: 0,
|
||||
posy: $sigTopY,
|
||||
width: $sigW,
|
||||
height: $sigH,
|
||||
offset: 3.0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [
|
||||
'all' => [
|
||||
'fillColor' => 'rgb(96%,96%,90%)',
|
||||
'lineColor' => 'rgb(35%,35%,10%)',
|
||||
'lineWidth' => 1.0,
|
||||
],
|
||||
],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
);
|
||||
|
||||
$pdf->signature()->appearance()->stream(stream: $sigAppearance);
|
||||
|
||||
// Render the signing process and the demo's limitations into the document so the
|
||||
// output PDF is self-documenting (this text is page content, not part of the
|
||||
// signed appearance stream).
|
||||
$explainHtml = <<<HTML
|
||||
<h2 style="font-size:11pt;color:#1f2a33;">How this PAdES-BASELINE-T signature is produced</h2>
|
||||
<p style="font-size:9pt;color:#1f2a33;">A B-T signature is a B-B signature (example E007) plus a signature
|
||||
timestamp. The library first builds the CAdES CMS, then sends the SignerInfo signature bytes to the TSA
|
||||
and embeds the returned RFC 3161 token in the CMS as the <code>id-aa-signatureTimeStampToken</code>
|
||||
unsigned attribute. The output CMS verifies over the <code>/ByteRange</code> bytes and carries a genuine
|
||||
TSA token that binds a trusted time to the signature.</p>
|
||||
<h2 style="font-size:11pt;color:#7a1f1f;">Limitations of this demo</h2>
|
||||
<ul style="font-size:9pt;color:#1f2a33;">
|
||||
<li>Timestamping performs a live RFC 3161 request to the TSA over HTTPS. The endpoint used here is the
|
||||
public freetsa.org demo service; use your own trusted TSA in production. The timestamp is mandatory
|
||||
for <code>pades-b-t</code> and above, so if the TSA is unreachable or rejects the request the signing
|
||||
step throws a signing exception and no PDF is produced.</li>
|
||||
<li>The bundled certificate is self-signed, so (as in E007) the signature is cryptographically valid
|
||||
but the signer identity is not trusted by viewers. The embedded timestamp itself is a real
|
||||
freetsa.org token and validates.</li>
|
||||
</ul>
|
||||
HTML;
|
||||
$pdf->addHTMLCell(html: $explainHtml, posx: 15, posy: 65, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E009_signature_ltv.php
|
||||
*
|
||||
* @since 2026-04-21
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 009');
|
||||
$pdf->setTitle('PAdES B-LT Long-Term Validation Signature Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example signature ltv dss vri pades pades-b-lt');
|
||||
$pdf->setPDFFilename('009_signature_ltv.pdf');
|
||||
|
||||
// Insert font before adding the first page.
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
|
||||
$page = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$text = 'This document is a PAdES-BASELINE-LT signature: B-T plus a Document Security Store (DSS).';
|
||||
$textCell = $pdf->getTextCell(
|
||||
txt: $text,
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell);
|
||||
|
||||
$text2 =
|
||||
'The DSS/VRI embed the certificate and, when its CA exposes reachable OCSP/CRL responders, '
|
||||
. 'the revocation data needed to verify offline long after expiry.';
|
||||
$textCell2 = $pdf->getTextCell(
|
||||
txt: $text2,
|
||||
posx: 15,
|
||||
posy: 27,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell2);
|
||||
|
||||
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
|
||||
if ($certPath === false) {
|
||||
throw new \RuntimeException('Missing signing certificate: examples/data/cert/tcpdf.crt');
|
||||
}
|
||||
|
||||
$cert = 'file://' . $certPath;
|
||||
|
||||
// PAdES-BASELINE-LT: a B-T signature (so a TSA timestamp is required) plus the
|
||||
// LTV material (DSS/VRI). The signing process and this demo's limitations are
|
||||
// rendered into the document itself (see the explanatory block added below).
|
||||
$pdf
|
||||
->signature()
|
||||
->configure([
|
||||
'profile' => 'pades-b-lt',
|
||||
'digest_algorithm' => 'sha256',
|
||||
'cert_type' => 2,
|
||||
'info' => [
|
||||
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
'Location' => 'Demo Office',
|
||||
'Name' => 'tc-lib-pdf',
|
||||
'Reason' => 'PAdES-BASELINE-LT (DSS/VRI) signature example',
|
||||
],
|
||||
'password' => '',
|
||||
'privkey' => $cert,
|
||||
'signcert' => $cert,
|
||||
'ltv' => [
|
||||
'enabled' => true,
|
||||
'embed_ocsp' => true,
|
||||
'embed_crl' => true,
|
||||
'embed_certs' => true,
|
||||
'include_dss' => true,
|
||||
'include_vri' => true,
|
||||
],
|
||||
])
|
||||
->timestamp([
|
||||
'enabled' => true,
|
||||
// Public demo endpoint. For production use your trusted TSA service.
|
||||
'host' => 'https://freetsa.org/tsr',
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'cert' => '',
|
||||
'hash_algorithm' => 'sha256',
|
||||
'policy_oid' => '',
|
||||
'nonce_enabled' => true,
|
||||
'timeout' => 30,
|
||||
'verify_peer' => true,
|
||||
]);
|
||||
|
||||
$pdf->signature()->appearance()->place(posx: 15, posy: 35, width: 90, height: 20, page: -1, name: 'LTVSignature');
|
||||
|
||||
// Attach a reusable Form XObject as signature appearance using the official API.
|
||||
// Any imported page can be used as a visual signature stamp.
|
||||
$stampSource = __DIR__ . '/data/pdf/E006_example_minimal.pdf';
|
||||
if (\is_readable($stampSource)) {
|
||||
$sourceId = $pdf->setImportSourceFile($stampSource);
|
||||
$tpl = $pdf->importPage(sourceId: $sourceId, pageNum: 1);
|
||||
$pdf->signature()->appearance()->xobject($tpl->getXobjId());
|
||||
} else {
|
||||
// Fallback appearance stream when the optional stamp source is unavailable.
|
||||
$sigW = 90.0;
|
||||
$sigH = 20.0;
|
||||
$sigTopY = $page['height'] - $sigH;
|
||||
|
||||
$sigAppearance = $bfont['out'];
|
||||
$sigAppearance .= $pdf->color->getPdfColor('rgb(15%,15%,15%)');
|
||||
$sigAppearance .= $pdf->getTextCell(
|
||||
txt: 'PAdES B-LT signature (DSS/VRI)',
|
||||
posx: 0,
|
||||
posy: $sigTopY,
|
||||
width: $sigW,
|
||||
height: $sigH,
|
||||
offset: 3.0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [
|
||||
'all' => [
|
||||
'fillColor' => 'rgb(94%,97%,92%)',
|
||||
'lineColor' => 'rgb(20%,40%,20%)',
|
||||
'lineWidth' => 1.0,
|
||||
],
|
||||
],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
);
|
||||
$pdf->signature()->appearance()->stream(stream: $sigAppearance);
|
||||
}
|
||||
|
||||
$widgetObjId = $pdf->signature()->widgetObjectId();
|
||||
$text3 = 'LTV signature widget object ID: ' . $widgetObjId;
|
||||
$textCell3 = $pdf->getTextCell(
|
||||
txt: $text3,
|
||||
posx: 15,
|
||||
posy: 60,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell3);
|
||||
|
||||
// Render the signing process and the demo's limitations into the document so the
|
||||
// output PDF is self-documenting (this text is page content, not part of the
|
||||
// signed appearance stream).
|
||||
$explainHtml = <<<HTML
|
||||
<h2 style="font-size:11pt;color:#1f2a33;">How this PAdES-BASELINE-LT signature is produced</h2>
|
||||
<p style="font-size:9pt;color:#1f2a33;">A B-LT signature is a B-T signature (a TSA timestamp is required)
|
||||
plus long-term validation material. The signing process writes two incremental revisions: first the
|
||||
CAdES signature with its embedded RFC 3161 signature timestamp (B-T), then a Document Security Store
|
||||
(<code>/DSS</code> with a <code>/VRI</code> map keyed by the uppercase SHA-1 of the final signature
|
||||
<code>/Contents</code>) carrying the validation material. OCSP/CRL retrieval follows the certificate's
|
||||
AIA and CRL-DP extensions so a validator can check the chain offline long after the certificate
|
||||
expires.</p>
|
||||
<h2 style="font-size:11pt;color:#7a1f1f;">Limitations of this demo</h2>
|
||||
<ul style="font-size:9pt;color:#1f2a33;">
|
||||
<li>A reachable TSA is required (live HTTPS request); if it is unreachable or rejects the request the
|
||||
signing step throws a signing exception and no PDF is produced.</li>
|
||||
<li>The bundled self-signed demo certificate exposes neither an OCSP responder nor a CRL distribution
|
||||
point, so the DSS embeds only the certificate bytes (no revocation data) and a validator reports B-T
|
||||
with a DSS present rather than a full B-LT. Missing responders are tolerated and do not abort signing.
|
||||
Sign with a CA-issued certificate whose OCSP/CRL responders are reachable at signing time to obtain a
|
||||
full B-LT verdict.</li>
|
||||
</ul>
|
||||
HTML;
|
||||
$pdf->addHTMLCell(html: $explainHtml, posx: 15, posy: 70, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E010_pdfx.php
|
||||
*
|
||||
* @since 2026-04-25
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfx,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 010');
|
||||
$pdf->setTitle('PDF/X Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example pdfx');
|
||||
$pdf->setPDFFilename('010_pdfx.pdf');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$page = $pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$html =
|
||||
'<h1>PDF/X</h1>'
|
||||
. '<p>Mode: pdfx</p>'
|
||||
. '<p>This generic alias currently maps to the library\'s baseline PDF/X print workflow.</p>'
|
||||
. '<p>Highlights: PDF/X identification metadata, print-oriented output intent handling, '
|
||||
. 'CMYK-oriented process colors, and suppression of interactive actions that are not allowed '
|
||||
. 'in a print-exchange profile.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E011_pdfx1a.php
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfx1a,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 011');
|
||||
$pdf->setTitle('PDF/X-1a Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example pdfx1a');
|
||||
$pdf->setPDFFilename('011_pdfx1a.pdf');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$html =
|
||||
'<h1>PDF/X-1a</h1>'
|
||||
. '<p>Mode: pdfx1a</p>'
|
||||
. '<p>PDF/X-1a targets an older, press-safe workflow centered on CMYK and spot colors.</p>'
|
||||
. '<p>Highlights: minimum PDF 1.3 output, transparency disabled, encryption disabled, '
|
||||
. 'and interactive annotations/actions suppressed for a classic print handoff.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E012_pdfx3.php
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfx3,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 012');
|
||||
$pdf->setTitle('PDF/X-3 Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example pdfx3');
|
||||
$pdf->setPDFFilename('012_pdfx3.pdf');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$html =
|
||||
'<h1>PDF/X-3</h1>'
|
||||
. '<p>Mode: pdfx3</p>'
|
||||
. '<p>PDF/X-3 keeps the print-exchange restrictions of early PDF/X while allowing '
|
||||
. 'color-managed workflows beyond device CMYK.</p>'
|
||||
. '<p>Highlights: minimum PDF 1.3 output, output-intent identification, no transparency, '
|
||||
. 'and no interactive actions that would conflict with print-only delivery.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E013_pdfx4.php
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfx4,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 013');
|
||||
$pdf->setTitle('PDF/X-4 Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example pdfx4');
|
||||
$pdf->setPDFFilename('013_pdfx4.pdf');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$html =
|
||||
'<h1>PDF/X-4</h1>'
|
||||
. '<p>Mode: pdfx4</p>'
|
||||
. '<p>PDF/X-4 modernizes print exchange by allowing live transparency in a color-managed workflow.</p>'
|
||||
. '<p>Highlights: minimum PDF 1.6 output, PDF/X-4 identification metadata, transparency retained, '
|
||||
. 'encryption disabled, and interactive actions still suppressed for print conformance.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E014_pdfx5.php
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfx5,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 014');
|
||||
$pdf->setTitle('PDF/X-5 Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example pdfx5');
|
||||
$pdf->setPDFFilename('014_pdfx5.pdf');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$html =
|
||||
'<h1>PDF/X-5</h1>'
|
||||
. '<p>Mode: pdfx5</p>'
|
||||
. '<p>PDF/X-5 builds on the PDF/X-4 family for more advanced print workflows and external references.</p>'
|
||||
. '<p>Highlights: minimum PDF 1.6 output, transparency retained, modern PDF/X identification, '
|
||||
. 'and the same print-safe suppression of unsupported interactive actions.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E015_pdfua.php
|
||||
*
|
||||
* Demonstrates HTML auto-tagging in 'pdfua' (generic alias) mode.
|
||||
*
|
||||
* Every HTML element rendered by addHTMLCell() is automatically mapped to the
|
||||
* corresponding PDF structure role — no beginStructElem() calls required.
|
||||
* Compare with E063 which builds the same structure tree manually via the
|
||||
* lower-level addTextCell() / beginStructElem() API.
|
||||
*
|
||||
* Auto-tagged roles exercised here:
|
||||
* h1-h3 → H1-H3 (heading hierarchy)
|
||||
* p → P (paragraph)
|
||||
* blockquote → BlockQuote
|
||||
* pre → Code
|
||||
* ul / ol → L (list; li → LI > Lbl + LBody auto-generated)
|
||||
* figure → Figure
|
||||
* img[alt] → Figure + /Alt (alt text written to struct-elem dictionary)
|
||||
* figcaption → Caption
|
||||
* table → Table (tr → TR, th → TH, td → TD, caption → Caption)
|
||||
* a → Link
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfua,
|
||||
);
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setTitle('PDF/UA Auto-Tagged HTML');
|
||||
$pdf->setSubject('tc-lib-pdf example: 015 — pdfua mode HTML tagging showcase');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf pdfua tagged PDF accessibility HTML auto-tag structure');
|
||||
$pdf->setPDFFilename('E015_pdfua.pdf');
|
||||
$pdf->setLanguage(code: 'en-US');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
// PDF/UA requires every font to be embedded. <code>/<pre> default to the
|
||||
// non-embedded standard-14 Courier, so register an embedded monospace font and
|
||||
// select it for those elements.
|
||||
$pdf->font->insert($pdf->pon, 'dejavusansmono', '', 10);
|
||||
$pdf->setHTMLMonospaceFont('dejavusansmono');
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$imgPath = __DIR__ . '/images/tcpdf_logo.jpg';
|
||||
|
||||
$html =
|
||||
'<h1>PDF/UA — Auto-Tagged HTML Showcase</h1>'
|
||||
. '<p>Mode: <strong>pdfua</strong> (generic alias). This document demonstrates every HTML'
|
||||
. ' element that <code>addHTMLCell()</code> auto-tags with a PDF structure role.'
|
||||
. ' No <code>beginStructElem()</code> calls are required: the library maps each HTML tag'
|
||||
. ' to its PDF role automatically when a PDF/UA mode is active. The generic'
|
||||
. ' <em>pdfua</em> alias behaves identically to <em>pdfua1</em> for structure-tree'
|
||||
. ' output and defaults to PDF 1.7.</p>'
|
||||
. '<h2>1 — Heading and Paragraph Roles</h2>'
|
||||
. '<h3>H3 Sub-heading</h3>'
|
||||
. '<p>The <code>h1</code>-<code>h6</code> tags map to PDF roles <strong>H1-H6</strong>.'
|
||||
. ' The <code>p</code> tag maps to <strong>P</strong>.'
|
||||
. ' Heading levels are clamped to prevent skipped levels in the structure tree,'
|
||||
. ' satisfying the PDF/UA requirement that no heading level may be skipped.</p>'
|
||||
. '<h2>2 — Block Roles</h2>'
|
||||
. '<blockquote>“Tagged PDF is the foundation of accessible PDF. Without a'
|
||||
. ' well-formed structure tree, automated tools and assistive technologies cannot'
|
||||
. ' reliably interpret document content.” — ISO 14289-1 rationale</blockquote>'
|
||||
. '<p>The <code>blockquote</code> tag maps to <strong>BlockQuote</strong>.</p>'
|
||||
. '<h2>3 — List Structure (L > LI > Lbl + LBody)</h2>'
|
||||
. '<p>Both <code>ul</code> and <code>ol</code> map to the <strong>L</strong> role.'
|
||||
. ' Each <code>li</code> auto-generates <strong>LI > {Lbl, LBody}</strong> children:</p>'
|
||||
. '<ul>'
|
||||
. '<li>Unordered item — <code>ul</code>/<code>li</code> tags produce L/LI structure</li>'
|
||||
. '<li>The bullet character is placed in a <strong>Lbl</strong> child element</li>'
|
||||
. '<li>Body text is wrapped in a <strong>LBody</strong> child element</li>'
|
||||
. '</ul>'
|
||||
. '<ol>'
|
||||
. '<li>Ordered item — the number is auto-generated as the <strong>Lbl</strong></li>'
|
||||
. '<li>Body text is again auto-wrapped in <strong>LBody</strong></li>'
|
||||
. '<li>Nesting: L > LI > {Lbl, LBody}</li>'
|
||||
. '</ol>'
|
||||
. '<h2>4 — Figure, Image Alt-Text, and Caption</h2>'
|
||||
. '<figure>'
|
||||
. '<img src="'
|
||||
. $imgPath
|
||||
. '" alt="TCPDF logo: blue text on white background" width="89" height="30" />'
|
||||
. '<figcaption>Figure 1 — TCPDF logo. The <code>alt</code> attribute is written as'
|
||||
. ' <strong>/Alt</strong> in the Figure structure-element dictionary so screen readers'
|
||||
. ' can describe the image. The <code>figcaption</code> tag maps to'
|
||||
. ' <strong>Caption</strong>.</figcaption>'
|
||||
. '</figure>'
|
||||
. '<h2>5 — Table Structure (Table > TR > TH/TD)</h2>'
|
||||
. '<table border="1" cellspacing="0" cellpadding="3">'
|
||||
. '<caption>Table 1 — HTML tags and their PDF/UA structure roles (auto-tagged by addHTMLCell)</caption>'
|
||||
. '<tr><th>HTML tag</th><th>PDF structure role</th><th>Category</th></tr>'
|
||||
. '<tr><td>h1–h6</td><td>H1–H6</td><td>Heading</td></tr>'
|
||||
. '<tr><td>p</td><td>P</td><td>Body</td></tr>'
|
||||
. '<tr><td>blockquote</td><td>BlockQuote</td><td>Body</td></tr>'
|
||||
. '<tr><td>pre</td><td>Code</td><td>Body</td></tr>'
|
||||
. '<tr><td>ul, ol</td><td>L</td><td>List</td></tr>'
|
||||
. '<tr><td>li</td><td>LI + Lbl + LBody</td><td>List</td></tr>'
|
||||
. '<tr><td>figure</td><td>Figure</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>img (with alt)</td><td>Figure + /Alt</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>figcaption, caption</td><td>Caption</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>table</td><td>Table</td><td>Table</td></tr>'
|
||||
. '<tr><td>tr</td><td>TR</td><td>Table</td></tr>'
|
||||
. '<tr><td>td</td><td>TD</td><td>Table</td></tr>'
|
||||
. '<tr><td>th</td><td>TH</td><td>Table</td></tr>'
|
||||
. '<tr><td>a</td><td>Link</td><td>Inline</td></tr>'
|
||||
. '</table>'
|
||||
. '<h2>6 — Hyperlink (Link Role)</h2>'
|
||||
. '<p>This sentence contains a'
|
||||
. ' <a href="https://github.com/tecnickcom/tc-lib-pdf" style="text-decoration:none;">hyperlink to the tc-lib-pdf repository</a>;'
|
||||
. ' the <code>a</code> element is tagged with the <strong>Link</strong> structure role'
|
||||
. ' automatically. The link text is accessible to screen readers via the structure tree.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E016_pdfua1.php
|
||||
*
|
||||
* Demonstrates HTML auto-tagging in 'pdfua1' (PDF/UA-1, ISO 14289-1) mode.
|
||||
*
|
||||
* PDF/UA-1 is the original accessible-PDF profile, standardised as ISO 14289-1:2012
|
||||
* and built on PDF 1.7. When this mode is active, tc-lib-pdf:
|
||||
* - Writes StructTreeRoot, ParentTree, and MarkInfo /Marked true
|
||||
* - Forces ViewerPreferences /DisplayDocTitle true
|
||||
* - Sets /Lang from the document language (default en-US)
|
||||
* - Clamps heading levels to prevent skipped H1-H6 levels
|
||||
* - Emits ActualText for ligatures and special glyphs
|
||||
*
|
||||
* Every HTML element rendered by addHTMLCell() is automatically mapped to the
|
||||
* corresponding PDF structure role — no beginStructElem() calls required.
|
||||
* Compare with E063 which builds the same structure tree manually.
|
||||
*
|
||||
* Auto-tagged roles exercised here:
|
||||
* h1-h3 → H1-H3 (heading hierarchy)
|
||||
* p → P (paragraph)
|
||||
* blockquote → BlockQuote
|
||||
* pre → Code
|
||||
* ul / ol → L (list; li → LI > Lbl + LBody auto-generated)
|
||||
* figure → Figure
|
||||
* img[alt] → Figure + /Alt (alt text written to struct-elem dictionary)
|
||||
* figcaption → Caption
|
||||
* table → Table (tr → TR, th → TH, td → TD, caption → Caption)
|
||||
* a → Link
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfua1,
|
||||
);
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setTitle('PDF/UA-1 Auto-Tagged HTML');
|
||||
$pdf->setSubject('tc-lib-pdf example: 016 — pdfua1 mode HTML tagging showcase');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf pdfua1 PDF/UA-1 ISO14289 tagged PDF accessibility HTML auto-tag');
|
||||
$pdf->setPDFFilename('E016_pdfua1.pdf');
|
||||
$pdf->setLanguage(code: 'en-US');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
// PDF/UA requires every font to be embedded. <code>/<pre> default to the
|
||||
// non-embedded standard-14 Courier, so register an embedded monospace font and
|
||||
// select it for those elements.
|
||||
$pdf->font->insert($pdf->pon, 'dejavusansmono', '', 10);
|
||||
$pdf->setHTMLMonospaceFont('dejavusansmono');
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$imgPath = __DIR__ . '/images/tcpdf_logo.jpg';
|
||||
|
||||
$html =
|
||||
'<h1>PDF/UA-1 — Auto-Tagged HTML Showcase</h1>'
|
||||
. '<p>Mode: <strong>pdfua1</strong> (ISO 14289-1, PDF 1.7). This document'
|
||||
. ' demonstrates every HTML element that <code>addHTMLCell()</code> auto-tags with a'
|
||||
. ' PDF/UA-1 structure role. PDF/UA-1 is the original accessible-PDF standard: it mandates'
|
||||
. ' a tagged structure tree, document language, <code>MarkInfo /Marked true</code>,'
|
||||
. ' and <code>ViewerPreferences /DisplayDocTitle true</code>. All of these are written'
|
||||
. ' automatically when the <em>pdfua1</em> mode is active.</p>'
|
||||
. '<h2>1 — Heading and Paragraph Roles</h2>'
|
||||
. '<h3>H3 Sub-heading</h3>'
|
||||
. '<p>The <code>h1</code>-<code>h6</code> tags map to PDF roles <strong>H1-H6</strong>.'
|
||||
. ' The <code>p</code> tag maps to <strong>P</strong>.'
|
||||
. ' PDF/UA-1 requires that heading levels are not skipped: the library clamps each'
|
||||
. ' heading to at most one level deeper than the previous heading to maintain a'
|
||||
. ' well-formed outline that screen readers can navigate.</p>'
|
||||
. '<h2>2 — Block Roles</h2>'
|
||||
. '<blockquote>“Tagged PDF is the foundation of accessible PDF. Without a'
|
||||
. ' well-formed structure tree, automated tools and assistive technologies cannot'
|
||||
. ' reliably interpret document content.” — ISO 14289-1 rationale</blockquote>'
|
||||
. '<p>The <code>blockquote</code> tag maps to <strong>BlockQuote</strong>.</p>'
|
||||
. '<h2>3 — List Structure (L > LI > Lbl + LBody)</h2>'
|
||||
. '<p>Both <code>ul</code> and <code>ol</code> map to the <strong>L</strong> role.'
|
||||
. ' Each <code>li</code> auto-generates <strong>LI > {Lbl, LBody}</strong> children:</p>'
|
||||
. '<ul>'
|
||||
. '<li>Unordered item — <code>ul</code>/<code>li</code> tags produce L/LI structure</li>'
|
||||
. '<li>The bullet character is placed in a <strong>Lbl</strong> child element</li>'
|
||||
. '<li>Body text is wrapped in a <strong>LBody</strong> child element</li>'
|
||||
. '</ul>'
|
||||
. '<ol>'
|
||||
. '<li>Ordered item — the number is auto-generated as the <strong>Lbl</strong></li>'
|
||||
. '<li>Body text is again auto-wrapped in <strong>LBody</strong></li>'
|
||||
. '<li>Nesting: L > LI > {Lbl, LBody}</li>'
|
||||
. '</ol>'
|
||||
. '<h2>4 — Figure, Image Alt-Text, and Caption</h2>'
|
||||
. '<figure>'
|
||||
. '<img src="'
|
||||
. $imgPath
|
||||
. '" alt="TCPDF logo: blue text on white background" width="89" height="30" />'
|
||||
. '<figcaption>Figure 1 — TCPDF logo. The <code>alt</code> attribute becomes'
|
||||
. ' <strong>/Alt</strong> in the Figure structure-element dictionary.'
|
||||
. ' PDF/UA-1 requires every Figure to carry an /Alt or /ActualText entry so'
|
||||
. ' screen readers can describe non-text content. The <code>figcaption</code> tag'
|
||||
. ' maps to <strong>Caption</strong>.</figcaption>'
|
||||
. '</figure>'
|
||||
. '<h2>5 — Table Structure (Table > TR > TH/TD)</h2>'
|
||||
. '<table border="1" cellspacing="0" cellpadding="3">'
|
||||
. '<caption>Table 1 — HTML tags and their PDF/UA-1 structure roles</caption>'
|
||||
. '<tr><th>HTML tag</th><th>PDF structure role</th><th>Category</th></tr>'
|
||||
. '<tr><td>h1–h6</td><td>H1–H6</td><td>Heading</td></tr>'
|
||||
. '<tr><td>p</td><td>P</td><td>Body</td></tr>'
|
||||
. '<tr><td>blockquote</td><td>BlockQuote</td><td>Body</td></tr>'
|
||||
. '<tr><td>pre</td><td>Code</td><td>Body</td></tr>'
|
||||
. '<tr><td>ul, ol</td><td>L</td><td>List</td></tr>'
|
||||
. '<tr><td>li</td><td>LI + Lbl + LBody</td><td>List</td></tr>'
|
||||
. '<tr><td>figure</td><td>Figure</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>img (with alt)</td><td>Figure + /Alt</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>figcaption, caption</td><td>Caption</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>table</td><td>Table</td><td>Table</td></tr>'
|
||||
. '<tr><td>tr</td><td>TR</td><td>Table</td></tr>'
|
||||
. '<tr><td>td</td><td>TD</td><td>Table</td></tr>'
|
||||
. '<tr><td>th</td><td>TH</td><td>Table</td></tr>'
|
||||
. '<tr><td>a</td><td>Link</td><td>Inline</td></tr>'
|
||||
. '</table>'
|
||||
. '<h2>6 — Hyperlink (Link Role)</h2>'
|
||||
. '<p>This sentence contains a'
|
||||
. ' <a href="https://github.com/tecnickcom/tc-lib-pdf" style="text-decoration:none;">hyperlink to the tc-lib-pdf repository</a>;'
|
||||
. ' the <code>a</code> element is tagged with the <strong>Link</strong> structure role'
|
||||
. ' automatically. PDF/UA-1 requires that link annotations have an accessible name,'
|
||||
. ' which the library derives from the link text in the structure tree.</p>'
|
||||
. '<h2>7 — Rules, Spans and Empty Cells</h2>'
|
||||
. '<p>A horizontal rule carries no semantics, so it is emitted as an <strong>Artifact</strong>'
|
||||
. ' rather than left as untagged content (PDF/UA-1 7.1):</p>'
|
||||
. '<hr>'
|
||||
. '<p>Cell <code>colspan</code>/<code>rowspan</code> are recorded on the cell structure'
|
||||
. ' element as integer <strong>/ColSpan</strong> and <strong>/RowSpan</strong> attributes,'
|
||||
. ' and an empty cell is kept in the tree so the row keeps its full column count (7.2):</p>'
|
||||
. '<table border="1" cellspacing="0" cellpadding="3">'
|
||||
. '<tr><th>Col A</th><th>Col B</th><th>Col C</th></tr>'
|
||||
. '<tr><td colspan="2">Spans columns A and B</td><td>C</td></tr>'
|
||||
. '<tr><td rowspan="2">Spans rows</td><td>B2</td><td>C2</td></tr>'
|
||||
. '<tr><td>B3</td><td></td></tr>'
|
||||
. '</table>';
|
||||
|
||||
// A long table that breaks across pages: the repeated header on each continuation
|
||||
// page is an Artifact, while the single Table structure element keeps all its rows.
|
||||
$html .=
|
||||
'<h2>8 — Page-Spanning Table</h2>'
|
||||
. '<table border="1" cellspacing="0" cellpadding="2">'
|
||||
. '<thead><tr><th>#</th><th>Description</th></tr></thead>';
|
||||
for ($row = 1; $row <= 60; ++$row) {
|
||||
$html .= '<tr><td>' . $row . '</td><td>Continuation row ' . $row . '</td></tr>';
|
||||
}
|
||||
|
||||
$html .= '</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E017_pdfua2.php
|
||||
*
|
||||
* Demonstrates HTML auto-tagging in 'pdfua2' (PDF/UA-2, ISO 14289-2) mode.
|
||||
*
|
||||
* PDF/UA-2 is the second generation of the accessible-PDF standard, standardised
|
||||
* as ISO 14289-2 and built on PDF 2.0. Key differences from PDF/UA-1:
|
||||
* - Targets PDF version 2.0 (pdfver 2.0 in catalog)
|
||||
* - Uses the PDF/UA-2 XMP identification schema
|
||||
* - The same structure-tree, MarkInfo, /Lang, and heading-clamping rules apply
|
||||
*
|
||||
* Every HTML element rendered by addHTMLCell() is automatically mapped to the
|
||||
* corresponding PDF structure role — no beginStructElem() calls required.
|
||||
* Compare with E063 which builds the same structure tree manually.
|
||||
*
|
||||
* Auto-tagged roles exercised here:
|
||||
* h1-h3 → H1-H3 (heading hierarchy)
|
||||
* p → P (paragraph)
|
||||
* blockquote → BlockQuote
|
||||
* pre → Code
|
||||
* ul / ol → L (list; li → LI > Lbl + LBody auto-generated)
|
||||
* figure → Figure
|
||||
* img[alt] → Figure + /Alt (alt text written to struct-elem dictionary)
|
||||
* figcaption → Caption
|
||||
* table → Table (tr → TR, th → TH, td → TD, caption → Caption)
|
||||
* a → Link
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfua2,
|
||||
);
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setTitle('PDF/UA-2 Auto-Tagged HTML');
|
||||
$pdf->setSubject('tc-lib-pdf example: 017 — pdfua2 mode HTML tagging showcase');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf pdfua2 PDF/UA-2 ISO14289-2 PDF2.0 tagged PDF accessibility HTML auto-tag');
|
||||
$pdf->setPDFFilename('E017_pdfua2.pdf');
|
||||
$pdf->setLanguage(code: 'en-US');
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
// PDF/UA requires every font to be embedded. <code>/<pre> default to the
|
||||
// non-embedded standard-14 Courier, so register an embedded monospace font and
|
||||
// select it for those elements.
|
||||
$pdf->font->insert($pdf->pon, 'dejavusansmono', '', 10);
|
||||
$pdf->setHTMLMonospaceFont('dejavusansmono');
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$imgPath = __DIR__ . '/images/tcpdf_logo.jpg';
|
||||
|
||||
$html =
|
||||
'<h1>PDF/UA-2 — Auto-Tagged HTML Showcase</h1>'
|
||||
. '<p>Mode: <strong>pdfua2</strong> (ISO 14289-2, PDF 2.0). This document'
|
||||
. ' demonstrates every HTML element that <code>addHTMLCell()</code> auto-tags with a'
|
||||
. ' PDF/UA-2 structure role. PDF/UA-2 advances the accessible-PDF standard onto the'
|
||||
. ' PDF 2.0 generation: it uses the updated PDF/UA-2 XMP identification schema'
|
||||
. ' and targets PDF version 2.0 while applying the same structure-tree, MarkInfo,'
|
||||
. ' /Lang, and heading-clamping rules as PDF/UA-1. The document infrastructure'
|
||||
. ' difference is transparent to the HTML tagging layer — all roles map identically.</p>'
|
||||
. '<h2>1 — Heading and Paragraph Roles</h2>'
|
||||
. '<h3>H3 Sub-heading</h3>'
|
||||
. '<p>The <code>h1</code>-<code>h6</code> tags map to PDF roles <strong>H1-H6</strong>.'
|
||||
. ' The <code>p</code> tag maps to <strong>P</strong>.'
|
||||
. ' Heading levels are clamped to prevent skipped levels: if an <code>h3</code>'
|
||||
. ' follows an <code>h1</code> without an intervening <code>h2</code>, the library'
|
||||
. ' silently promotes it to H2 so the PDF/UA heading-nesting rule is not violated.</p>'
|
||||
. '<h2>2 — Block Roles</h2>'
|
||||
. '<blockquote>“Tagged PDF is the foundation of accessible PDF. Without a'
|
||||
. ' well-formed structure tree, automated tools and assistive technologies cannot'
|
||||
. ' reliably interpret document content.” — ISO 14289 rationale</blockquote>'
|
||||
. '<p>The <code>blockquote</code> tag maps to <strong>BlockQuote</strong>.</p>'
|
||||
. '<h2>3 — List Structure (L > LI > Lbl + LBody)</h2>'
|
||||
. '<p>Both <code>ul</code> and <code>ol</code> map to the <strong>L</strong> role.'
|
||||
. ' Each <code>li</code> auto-generates <strong>LI > {Lbl, LBody}</strong> children:</p>'
|
||||
. '<ul>'
|
||||
. '<li>Unordered item — <code>ul</code>/<code>li</code> tags produce L/LI structure</li>'
|
||||
. '<li>The bullet character is placed in a <strong>Lbl</strong> child element</li>'
|
||||
. '<li>Body text is wrapped in a <strong>LBody</strong> child element</li>'
|
||||
. '</ul>'
|
||||
. '<ol>'
|
||||
. '<li>Ordered item — the number is auto-generated as the <strong>Lbl</strong></li>'
|
||||
. '<li>Body text is again auto-wrapped in <strong>LBody</strong></li>'
|
||||
. '<li>Nesting: L > LI > {Lbl, LBody}</li>'
|
||||
. '</ol>'
|
||||
. '<h2>4 — Figure, Image Alt-Text, and Caption</h2>'
|
||||
. '<figure>'
|
||||
. '<img src="'
|
||||
. $imgPath
|
||||
. '" alt="TCPDF logo: blue text on white background" width="89" height="30" />'
|
||||
. '<figcaption>Figure 1 — TCPDF logo. The <code>alt</code> attribute becomes'
|
||||
. ' <strong>/Alt</strong> in the Figure structure-element dictionary.'
|
||||
. ' PDF/UA-2 (like PDF/UA-1) requires every Figure to carry an /Alt or'
|
||||
. ' /ActualText entry. The <code>figcaption</code> tag maps to'
|
||||
. ' <strong>Caption</strong>.</figcaption>'
|
||||
. '</figure>'
|
||||
. '<h2>5 — Table Structure (Table > TR > TH/TD)</h2>'
|
||||
. '<table border="1" cellspacing="0" cellpadding="3">'
|
||||
. '<caption>Table 1 — HTML tags and their PDF/UA-2 structure roles</caption>'
|
||||
. '<tr><th>HTML tag</th><th>PDF structure role</th><th>Category</th></tr>'
|
||||
. '<tr><td>h1–h6</td><td>H1–H6</td><td>Heading</td></tr>'
|
||||
. '<tr><td>p</td><td>P</td><td>Body</td></tr>'
|
||||
. '<tr><td>blockquote</td><td>BlockQuote</td><td>Body</td></tr>'
|
||||
. '<tr><td>pre</td><td>Code</td><td>Body</td></tr>'
|
||||
. '<tr><td>ul, ol</td><td>L</td><td>List</td></tr>'
|
||||
. '<tr><td>li</td><td>LI + Lbl + LBody</td><td>List</td></tr>'
|
||||
. '<tr><td>figure</td><td>Figure</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>img (with alt)</td><td>Figure + /Alt</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>figcaption, caption</td><td>Caption</td><td>Illustration</td></tr>'
|
||||
. '<tr><td>table</td><td>Table</td><td>Table</td></tr>'
|
||||
. '<tr><td>tr</td><td>TR</td><td>Table</td></tr>'
|
||||
. '<tr><td>td</td><td>TD</td><td>Table</td></tr>'
|
||||
. '<tr><td>th</td><td>TH</td><td>Table</td></tr>'
|
||||
. '<tr><td>a</td><td>Link</td><td>Inline</td></tr>'
|
||||
. '</table>'
|
||||
. '<h2>6 — Hyperlink (Link Role)</h2>'
|
||||
. '<p>This sentence contains a'
|
||||
. ' <a href="https://github.com/tecnickcom/tc-lib-pdf" style="text-decoration:none;">hyperlink to the tc-lib-pdf repository</a>;'
|
||||
. ' the <code>a</code> element is tagged with the <strong>Link</strong> structure role'
|
||||
. ' automatically. In PDF/UA-2 (as in PDF/UA-1), link annotations must be accessible;'
|
||||
. ' the library derives the accessible name from the link text in the structure tree.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E018_html_page_span.php
|
||||
*
|
||||
* @since 2026-04-25
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 018');
|
||||
$pdf->setTitle('HTML Page Span Handling');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf html page span pagination flow layout');
|
||||
$pdf->setPDFFilename('018_html_page_span.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
$pageV01 = $pdf->addPage();
|
||||
|
||||
$bfont6 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
$pdf->page->addContent($bfont6['out']);
|
||||
|
||||
$html = 'Some special characters: < € € € & è è © > \\slash \\\\double-slash \\\\\\triple-slash
|
||||
<h2>List</h2>
|
||||
List example:
|
||||
<ol>
|
||||
<li><b>bold text</b></li>
|
||||
<li><i>italic text</i></li>
|
||||
<li><u>underlined text</u></li>
|
||||
<li><b>b<i>bi<u>biu</u>bi</i>b</b></li>
|
||||
<li><a href="https://tcpdf.org" dir="ltr">link to https://tcpdf.org</a></li>
|
||||
<li>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.<br />Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</li>
|
||||
<li>SUBLIST
|
||||
<ol>
|
||||
<li>row one
|
||||
<ul>
|
||||
<li>sublist</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>row two</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><b>T</b>E<i>S</i><u>T</u> <del>line through</del></li>
|
||||
<li><font size="+3">font + 3</font></li>
|
||||
<li><small>small text</small> normal <small>small text</small> normal <sub>subscript</sub> normal <sup>superscript</sup> normal</li>
|
||||
</ol>
|
||||
<dl>
|
||||
<dt>Coffee</dt>
|
||||
<dd>Black hot drink</dd>
|
||||
<dt>Milk</dt>
|
||||
<dd>White cold drink</dd>
|
||||
</dl>
|
||||
|
||||
<div style="text-align:center">The words “<span dir="rtl">מזל [mazel] טוב [tov]</span>” mean “Congratulations!”</div>
|
||||
|
||||
<p>This is just an example of html code to demonstrate some supported CSS inline styles.
|
||||
<span style="font-weight: bold;">bold text</span>
|
||||
<span style="text-decoration: line-through;">line-trough</span>
|
||||
<span style="text-decoration: underline line-through;">underline and line-trough</span>
|
||||
<span style="color: rgb(0, 128, 64);">color</span>
|
||||
<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">background color</span>
|
||||
<span style="font-weight: bold;">bold</span>
|
||||
<span style="font-size: xx-small;">xx-small</span>
|
||||
<span style="font-size: x-small;">x-small</span>
|
||||
<span style="font-size: small;">small</span>
|
||||
<span style="font-size: medium;">medium</span>
|
||||
<span style="font-size: large;">large</span>
|
||||
<span style="font-size: x-large;">x-large</span>
|
||||
<span style="font-size: xx-large;">xx-large</span>
|
||||
</p>';
|
||||
|
||||
$pdf->addHTMLCell(
|
||||
html: '<h1>HTML page break example</h1>' . $html . $html . $html . $html,
|
||||
posx: 20,
|
||||
posy: 10,
|
||||
width: 150,
|
||||
);
|
||||
|
||||
// =============================================================
|
||||
// Styled block (background + border) spanning multiple pages.
|
||||
|
||||
$blockchunk =
|
||||
'<p>'
|
||||
. 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium '
|
||||
. 'doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore '
|
||||
. 'veritatis et quasi architecto beatae vitae dicta sunt explicabo.'
|
||||
. '</p>';
|
||||
|
||||
$blockhtml =
|
||||
'<h2>Styled block across pages</h2>'
|
||||
. '<div style="background-color:#ffeeaa;border:1px solid #888;padding:4px">'
|
||||
. '<p><b>Block-level container</b> — the background and border continue '
|
||||
. 'on each page until the content ends.</p>'
|
||||
. \str_repeat($blockchunk, 30)
|
||||
. '</div>';
|
||||
|
||||
$pdf->addHTMLCell(html: $blockhtml, posx: 20, posy: 100, width: 150);
|
||||
|
||||
// =============================================================
|
||||
// Table spanning multiple pages with header row replay.
|
||||
|
||||
$tableRows = '';
|
||||
for ($i = 1; $i <= 20; ++$i) {
|
||||
$tableRows .=
|
||||
'<tr>'
|
||||
. '<td>'
|
||||
. $i
|
||||
. '</td>'
|
||||
. '<td>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</td>'
|
||||
. '<td style="text-align:right">'
|
||||
. \number_format($i * 12.34, 2)
|
||||
. '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
|
||||
$tablehtml =
|
||||
'<h2>Table across pages</h2>'
|
||||
. '<table border="1" cellpadding="3" cellspacing="0">'
|
||||
. '<thead>'
|
||||
. '<tr style="background-color:#cccccc">'
|
||||
. '<th>#</th><th>Description</th><th>Amount</th>'
|
||||
. '</tr>'
|
||||
. '</thead>'
|
||||
. $tableRows
|
||||
. '</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $tablehtml, posx: 20, posy: 220, width: 150);
|
||||
|
||||
// =============================================================
|
||||
// Table rows containing DIV blocks with an explicit CSS height.
|
||||
// Odd rows use a styled DIV (text color + background color), even rows
|
||||
// use a bare DIV with only the height set: both must produce the same
|
||||
// row height, and no row may be split across pages.
|
||||
|
||||
$tableRowsB = '';
|
||||
for ($i = 1; $i <= 8; ++$i) {
|
||||
$divstyleB = ($i % 2) === 1 ? 'color:blue; background-color:yellow; height:100px;' : 'color:#007700; height:100px;';
|
||||
$tableRowsB .=
|
||||
'<tr>'
|
||||
. '<td>'
|
||||
. $i
|
||||
. '</td>'
|
||||
. '<td><div style="'
|
||||
. $divstyleB
|
||||
. '">DIV block #'
|
||||
. $i
|
||||
. ' (100px high)</div></td>'
|
||||
. '<td style="text-align:right">'
|
||||
. \number_format($i * 12.34, 2)
|
||||
. '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
|
||||
$tablehtmlB =
|
||||
'<h2>Fixed-height DIV blocks inside table cells</h2>'
|
||||
. '<table border="1" cellpadding="3" cellspacing="0">'
|
||||
. '<thead>'
|
||||
. '<tr style="background-color:#cccccc">'
|
||||
. '<th>#</th><th>Description</th><th>Amount</th>'
|
||||
. '</tr>'
|
||||
. '</thead>'
|
||||
. $tableRowsB
|
||||
. '</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $tablehtmlB, posx: 20, posy: 170, width: 150);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E019_page_regions.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 019');
|
||||
$pdf->setTitle('Page regions example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example page regions columns');
|
||||
$pdf->setPDFFilename('019_page_regions.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$titlefont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 12);
|
||||
$textfont = $pdf->font->insert($pdf->pon, 'times', '', 11);
|
||||
|
||||
// ----------
|
||||
// Two text regions (columns) generated from the content area.
|
||||
|
||||
$leftMargin = 15.0;
|
||||
$rightMargin = 15.0;
|
||||
$topMargin = 20.0;
|
||||
$bottomMargin = 20.0;
|
||||
$columnGap = 8.0;
|
||||
|
||||
$contentWidth = 210.0 - $leftMargin - $rightMargin;
|
||||
$contentHeight = 297.0 - $topMargin - $bottomMargin;
|
||||
$columnWidth = ($contentWidth - $columnGap) / 2.0;
|
||||
|
||||
$page = $pdf->addPage([
|
||||
'margin' => [
|
||||
'PL' => $leftMargin,
|
||||
'PR' => $rightMargin,
|
||||
'CT' => $topMargin,
|
||||
'CB' => $bottomMargin,
|
||||
],
|
||||
'region' => [
|
||||
[
|
||||
'RX' => $leftMargin,
|
||||
'RY' => $topMargin,
|
||||
'RW' => $columnWidth,
|
||||
'RH' => $contentHeight,
|
||||
],
|
||||
[
|
||||
'RX' => $leftMargin + $columnWidth + $columnGap,
|
||||
'RY' => $topMargin,
|
||||
'RW' => $columnWidth,
|
||||
'RH' => $contentHeight,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$pdf->page->addContent($titlefont['out']);
|
||||
$pdf->addTextCell(
|
||||
txt: 'Page Regions: two flowing columns across pages',
|
||||
pid: $page['pid'],
|
||||
posx: 0, // NOTE: addTextCell() coordinates are relative to the current page region
|
||||
posy: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
$pdf->page->addContent($textfont['out']);
|
||||
|
||||
$leftPrefix =
|
||||
'LEFT/RIGHT REGION FLOW. This paragraph is rendered using page regions. '
|
||||
. 'When the first region is full, writing continues in the next region, '
|
||||
. 'then on the next page with the same two-region layout. ';
|
||||
|
||||
$baseParagraph =
|
||||
'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque '
|
||||
. 'laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto '
|
||||
. 'beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut '
|
||||
. 'odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. '
|
||||
. 'Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.';
|
||||
|
||||
$chunks = [];
|
||||
for ($idx = 1; $idx <= 20; ++$idx) {
|
||||
$chunks[] = 'Section ' . $idx . '. ' . $leftPrefix . $baseParagraph;
|
||||
}
|
||||
|
||||
$content = "Two columns with automatic region/page breaks\n\n" . \implode("\n\n", $chunks);
|
||||
|
||||
$region = $pdf->page->getRegion($page['pid']);
|
||||
$regionWidth = (float) $region['RW'];
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: $content,
|
||||
pid: $page['pid'],
|
||||
posx: 0,
|
||||
posy: 12,
|
||||
width: $regionWidth,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
// --- Same example using HTML ---
|
||||
|
||||
$pageH = $pdf->addPage([
|
||||
'margin' => [
|
||||
'PL' => $leftMargin,
|
||||
'PR' => $rightMargin,
|
||||
'CT' => $topMargin,
|
||||
'CB' => $bottomMargin,
|
||||
],
|
||||
'region' => [
|
||||
[
|
||||
'RX' => $leftMargin,
|
||||
'RY' => $topMargin,
|
||||
'RW' => $columnWidth,
|
||||
'RH' => $contentHeight,
|
||||
],
|
||||
[
|
||||
'RX' => $leftMargin + $columnWidth + $columnGap,
|
||||
'RY' => $topMargin,
|
||||
'RW' => $columnWidth,
|
||||
'RH' => $contentHeight,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$contentHtml =
|
||||
'<p>'
|
||||
. \str_replace("\n\n", '</p><p>', \htmlspecialchars($content, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8'))
|
||||
. '</p>';
|
||||
|
||||
$pdf->page->selectRegion(0, $pageH['pid']);
|
||||
$regionH = $pdf->page->getRegion($pageH['pid']);
|
||||
|
||||
$pdf->addHTMLCell(
|
||||
html: $contentHtml,
|
||||
posx: (float) $regionH['RX'],
|
||||
posy: (float) $regionH['RY'],
|
||||
width: (float) $regionH['RW'],
|
||||
);
|
||||
|
||||
// --- Test add addTextCellXY() for absolute page coordinates ---
|
||||
|
||||
$page = $pdf->addPage([
|
||||
'margin' => [
|
||||
'PL' => 15.0,
|
||||
'PR' => 15.0,
|
||||
'CT' => 15.0,
|
||||
'CB' => 15.0,
|
||||
],
|
||||
]);
|
||||
|
||||
$pdf->addTextCellXY(
|
||||
txt: 'addTextCellXY() uses absolute page coordinates [X=0, Y=0].',
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: 'addTextCell() uses relative page region coordinates [x=0, y=0] => [X=15, Y=15].',
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
// =============================================================
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,554 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E020_barcodes.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 020');
|
||||
$pdf->setTitle('All Barcode Types Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example barcodes 1D 2D');
|
||||
$pdf->setPDFFilename('020_barcodes.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$titlefont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 12);
|
||||
$textfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 9);
|
||||
$smallfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 8);
|
||||
|
||||
$style = [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'black',
|
||||
'fillColor' => 'black',
|
||||
];
|
||||
|
||||
$linear = [
|
||||
[
|
||||
'type' => 'C128A',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 128 Set A',
|
||||
'standard' => 'ISO/IEC 15417',
|
||||
'use' => 'High-density linear code for control characters, logistics, and internal labeling.',
|
||||
],
|
||||
[
|
||||
'type' => 'C128B',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 128 Set B',
|
||||
'standard' => 'ISO/IEC 15417',
|
||||
'use' => 'High-density linear code for mixed upper/lower-case text in shipping and warehousing.',
|
||||
],
|
||||
[
|
||||
'type' => 'C128C',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 128 Set C',
|
||||
'standard' => 'ISO/IEC 15417',
|
||||
'use' => 'Numeric-optimized Code 128 variant for compact encoded numbers and IDs.',
|
||||
],
|
||||
[
|
||||
'type' => 'C128',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 128 (Auto)',
|
||||
'standard' => 'ISO/IEC 15417',
|
||||
'use' => 'General-purpose high-density linear symbology with automatic charset selection.',
|
||||
],
|
||||
[
|
||||
'type' => 'C39E+',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 39 Extended + checksum',
|
||||
'standard' => 'ANSI MH10.8M / USS Code 39',
|
||||
'use' => 'Extended Code 39 character support with checksum for asset tags and internal IDs.',
|
||||
],
|
||||
[
|
||||
'type' => 'C39E',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 39 Extended',
|
||||
'standard' => 'ANSI MH10.8M / USS Code 39',
|
||||
'use' => 'Expanded Code 39 set used for industrial and inventory labels.',
|
||||
],
|
||||
[
|
||||
'type' => 'C39+',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 39 + checksum',
|
||||
'standard' => 'ANSI MH10.8M / USS Code 39',
|
||||
'use' => 'Code 39 with checksum to improve scan reliability in production environments.',
|
||||
],
|
||||
[
|
||||
'type' => 'C39',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 39',
|
||||
'standard' => 'ANSI MH10.8M-1983 (USD-3 / 3 of 9)',
|
||||
'use' => 'Classic alphanumeric barcode used for parts, equipment, and non-retail logistics.',
|
||||
],
|
||||
[
|
||||
'type' => 'C93',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 93',
|
||||
'standard' => 'USS-93',
|
||||
'use' => 'Compact linear code often used where Code 39 would be too wide.',
|
||||
],
|
||||
[
|
||||
'type' => 'CODABAR',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Codabar',
|
||||
'standard' => 'NW-7 (legacy)',
|
||||
'use' => 'Legacy symbology used in libraries, blood banks, and some healthcare systems.',
|
||||
],
|
||||
[
|
||||
'type' => 'CODE11',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Code 11',
|
||||
'standard' => 'USD-8 (legacy)',
|
||||
'use' => 'Numeric code widely used in telecommunications and labeling of equipment.',
|
||||
],
|
||||
[
|
||||
'type' => 'EAN13',
|
||||
'code' => '0123456789',
|
||||
'name' => 'EAN-13',
|
||||
'standard' => 'GS1 EAN/UPC',
|
||||
'use' => 'Global retail product identification barcode used on consumer goods.',
|
||||
],
|
||||
[
|
||||
'type' => 'EAN2',
|
||||
'code' => '12',
|
||||
'name' => 'EAN 2-digit add-on',
|
||||
'standard' => 'GS1 EAN/UPC add-on',
|
||||
'use' => 'Supplementary add-on commonly used to encode issue numbers for periodicals.',
|
||||
],
|
||||
[
|
||||
'type' => 'EAN5',
|
||||
'code' => '12345',
|
||||
'name' => 'EAN 5-digit add-on',
|
||||
'standard' => 'GS1 EAN/UPC add-on',
|
||||
'use' => 'Supplementary add-on often used for suggested retail pricing on books/magazines.',
|
||||
],
|
||||
[
|
||||
'type' => 'EAN8',
|
||||
'code' => '1234567',
|
||||
'name' => 'EAN-8',
|
||||
'standard' => 'GS1 EAN/UPC',
|
||||
'use' => 'Compact retail barcode for very small consumer packages.',
|
||||
],
|
||||
[
|
||||
'type' => 'I25+',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Interleaved 2 of 5 + checksum',
|
||||
'standard' => 'ITF / Interleaved 2 of 5',
|
||||
'use' => 'Numeric shipping and carton labels with checksum for improved integrity.',
|
||||
],
|
||||
[
|
||||
'type' => 'I25',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Interleaved 2 of 5',
|
||||
'standard' => 'ITF / Interleaved 2 of 5',
|
||||
'use' => 'Numeric-only barcode frequently used on corrugated packaging.',
|
||||
],
|
||||
[
|
||||
'type' => 'IMB',
|
||||
'code' => '01234567094987654321-01234567891',
|
||||
'name' => 'Intelligent Mail Barcode',
|
||||
'standard' => 'USPS-B-3200',
|
||||
'use' => 'USPS mail sorting and tracking barcode for letters and flats.',
|
||||
],
|
||||
[
|
||||
'type' => 'IMBPRE',
|
||||
'code' => 'AADTFFDFTDADTAADAATFDTDDAAADDTDTTDAFADADDDTFFFDDTTTADFAAADFTDAADA',
|
||||
'name' => 'IMB pre-processed',
|
||||
'standard' => 'USPS Intelligent Mail (pre-encoded pattern)',
|
||||
'use' => 'Feeds a precomputed IMB state pattern when encoding is prepared upstream.',
|
||||
],
|
||||
[
|
||||
'type' => 'KIX',
|
||||
'code' => '0123456789',
|
||||
'name' => 'KIX',
|
||||
'standard' => 'PostNL KIX (4-state)',
|
||||
'use' => 'Dutch postal customer indexing and routing barcode.',
|
||||
],
|
||||
[
|
||||
'type' => 'MSI+',
|
||||
'code' => '0123456789',
|
||||
'name' => 'MSI + checksum',
|
||||
'standard' => 'MSI Plessey (variant)',
|
||||
'use' => 'Inventory-oriented numeric coding with checksum for warehouse workflows.',
|
||||
],
|
||||
[
|
||||
'type' => 'MSI',
|
||||
'code' => '0123456789',
|
||||
'name' => 'MSI',
|
||||
'standard' => 'MSI Plessey (variant)',
|
||||
'use' => 'Numeric barcode used in stock control and shelf labeling.',
|
||||
],
|
||||
[
|
||||
'type' => 'PHARMA2T',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Pharmacode two-track',
|
||||
'standard' => 'Pharmacode (2-track variant)',
|
||||
'use' => 'Pharmaceutical package line verification using two-track bar patterns.',
|
||||
],
|
||||
[
|
||||
'type' => 'PHARMA',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Pharmacode',
|
||||
'standard' => 'Laetus Pharmacode',
|
||||
'use' => 'Pharmaceutical packaging control on production lines.',
|
||||
],
|
||||
[
|
||||
'type' => 'PLANET',
|
||||
'code' => '0123456789',
|
||||
'name' => 'PLANET',
|
||||
'standard' => 'USPS PLANET (legacy)',
|
||||
'use' => 'Legacy USPS mail tracking and routing barcode.',
|
||||
],
|
||||
[
|
||||
'type' => 'POSTNET',
|
||||
'code' => '0123456789',
|
||||
'name' => 'POSTNET',
|
||||
'standard' => 'USPS POSTNET (legacy)',
|
||||
'use' => 'Legacy USPS ZIP and delivery-point encoding for mail sorting.',
|
||||
],
|
||||
[
|
||||
'type' => 'RMS4CC',
|
||||
'code' => '0123456789',
|
||||
'name' => 'RMS4CC',
|
||||
'standard' => 'Royal Mail 4-State Customer Code',
|
||||
'use' => 'UK postal addressing and sorting barcode.',
|
||||
],
|
||||
[
|
||||
'type' => 'S25+',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Standard 2 of 5 + checksum',
|
||||
'standard' => 'Standard 2 of 5 (industrial)',
|
||||
'use' => 'Numeric industrial barcode with checksum for improved reliability.',
|
||||
],
|
||||
[
|
||||
'type' => 'S25',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Standard 2 of 5',
|
||||
'standard' => 'Standard 2 of 5 (industrial)',
|
||||
'use' => 'Legacy numeric industrial labeling barcode.',
|
||||
],
|
||||
[
|
||||
'type' => 'UPCA',
|
||||
'code' => '72527273070',
|
||||
'name' => 'UPC-A',
|
||||
'standard' => 'GS1 EAN/UPC',
|
||||
'use' => 'Retail barcode primarily used in North America.',
|
||||
],
|
||||
[
|
||||
'type' => 'UPCE',
|
||||
'code' => '725277',
|
||||
'name' => 'UPC-E',
|
||||
'standard' => 'GS1 EAN/UPC',
|
||||
'use' => 'Compressed UPC format for small retail packages.',
|
||||
],
|
||||
];
|
||||
|
||||
$square = [
|
||||
[
|
||||
'type' => 'LRAW',
|
||||
'code' => '0101010101',
|
||||
'name' => '1D raw mode',
|
||||
'standard' => 'Library raw mode (non-standard)',
|
||||
'use' => 'Debug/test mode that directly renders provided 1D bit patterns.',
|
||||
],
|
||||
[
|
||||
'type' => 'SRAW',
|
||||
'code' => '0101,1010',
|
||||
'name' => '2D raw mode',
|
||||
'standard' => 'Library raw mode (non-standard)',
|
||||
'use' => 'Debug/test mode that directly renders provided 2D bit grids.',
|
||||
],
|
||||
[
|
||||
'type' => 'AZTEC',
|
||||
'code' => 'ABCDabcd01234',
|
||||
'name' => 'Aztec Code',
|
||||
'standard' => 'ISO/IEC 24778:2008',
|
||||
'use' => 'Compact 2D code used for tickets, transport passes, and mobile scans.',
|
||||
],
|
||||
[
|
||||
'type' => 'AZTEC,50,A,A',
|
||||
'code' => 'ABCDabcd01234',
|
||||
'name' => 'Aztec Code (with parameters)',
|
||||
'standard' => 'ISO/IEC 24778:2008',
|
||||
'use' => 'Aztec variant with explicit encoder parameters for size/error tuning.',
|
||||
],
|
||||
[
|
||||
'type' => 'PDF417',
|
||||
'code' => '0123456789',
|
||||
'name' => 'PDF417',
|
||||
'standard' => 'ISO/IEC 15438:2006',
|
||||
'use' => 'Stacked 2D barcode used in transport, identity, and archival workflows.',
|
||||
],
|
||||
[
|
||||
'type' => 'QRCODE',
|
||||
'code' => '0123456789',
|
||||
'name' => 'QR Code',
|
||||
'standard' => 'ISO/IEC 18004',
|
||||
'use' => 'Widely used 2D code for URLs, mobile interactions, and consumer scanning.',
|
||||
],
|
||||
[
|
||||
'type' => 'QRCODE,H,ST,0,0',
|
||||
'code' => 'abcdefghijklmnopqrstuvwxy0123456789',
|
||||
'name' => 'QR Code (with parameters)',
|
||||
'standard' => 'ISO/IEC 18004',
|
||||
'use' => 'QR variant with explicit error correction and encoding parameters.',
|
||||
],
|
||||
[
|
||||
'type' => 'DATAMATRIX',
|
||||
'code' => '0123456789',
|
||||
'name' => 'Data Matrix (square)',
|
||||
'standard' => 'ISO/IEC 16022',
|
||||
'use' => 'Compact 2D marking used in electronics, medical devices, and manufacturing.',
|
||||
],
|
||||
[
|
||||
'type' => 'DATAMATRIX,R',
|
||||
'code' => '0123456789012345678901234567890123456789',
|
||||
'name' => 'Data Matrix (rectangular)',
|
||||
'standard' => 'ISO/IEC 16022',
|
||||
'use' => 'Rectangular Data Matrix for narrow labels and constrained print areas.',
|
||||
],
|
||||
[
|
||||
'type' => 'DATAMATRIX,S,GS1',
|
||||
'code' => \chr(232) . '01095011010209171719050810ABCD1234' . \chr(232) . '2110',
|
||||
'name' => 'GS1 Data Matrix (square)',
|
||||
'standard' => 'ISO/IEC 16022 with GS1 AIs',
|
||||
'use' => 'GS1-compliant 2D code for regulated product IDs and traceability.',
|
||||
],
|
||||
[
|
||||
'type' => 'DATAMATRIX,R,GS1',
|
||||
'code' => \chr(232) . '01095011010209171719050810ABCD1234' . \chr(232) . '2110',
|
||||
'name' => 'GS1 Data Matrix (rectangular)',
|
||||
'standard' => 'ISO/IEC 16022 with GS1 AIs',
|
||||
'use' => 'Rectangular GS1 Data Matrix for compact traceability labels.',
|
||||
],
|
||||
];
|
||||
|
||||
function formatSampleDataForText(string $sample): string
|
||||
{
|
||||
$out = '';
|
||||
$bytes = \unpack('C*', $sample);
|
||||
if ($bytes === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach ($bytes as $byte) {
|
||||
if ($byte === 232) {
|
||||
$out .= '<FNC1>';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($byte >= 32 && $byte <= 126) {
|
||||
$out .= \chr($byte);
|
||||
continue;
|
||||
}
|
||||
|
||||
$out .= '\\x' . \strtoupper(\str_pad((string) \dechex($byte), 2, '0', STR_PAD_LEFT));
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
function renderBarcodeSection(
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
array $items,
|
||||
string $title,
|
||||
int $sectionIndex,
|
||||
array $titlefont,
|
||||
array $textfont,
|
||||
array $smallfont,
|
||||
array $style,
|
||||
bool $square = false,
|
||||
): void {
|
||||
$marginLeft = 12.0;
|
||||
$marginRight = 12.0;
|
||||
$marginTop = 15.0;
|
||||
$marginBottom = 12.0;
|
||||
|
||||
$page = $pdf->addPage([
|
||||
'margin' => [
|
||||
'PL' => $marginLeft,
|
||||
'PR' => $marginRight,
|
||||
'CT' => $marginTop,
|
||||
'CB' => $marginBottom,
|
||||
],
|
||||
]);
|
||||
|
||||
$pageWidth = (float) $page['width'];
|
||||
$pageHeight = (float) $page['height'];
|
||||
$contentWidth = $pageWidth - $marginLeft - $marginRight;
|
||||
$maxY = $pageHeight - $marginBottom;
|
||||
|
||||
$drawHeader = static function () use (
|
||||
$pdf,
|
||||
$titlefont,
|
||||
$smallfont,
|
||||
$title,
|
||||
$sectionIndex,
|
||||
$marginLeft,
|
||||
$contentWidth,
|
||||
): float {
|
||||
$pdf->page->addContent($titlefont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Barcode Types Catalog (' . $sectionIndex . '/2): ' . $title,
|
||||
posx: $marginLeft,
|
||||
posy: 10,
|
||||
width: $contentWidth,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($smallfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Source type list: tc-lib-barcode example/index.php',
|
||||
posx: $marginLeft,
|
||||
posy: 16,
|
||||
width: $contentWidth,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
return 22.0;
|
||||
};
|
||||
|
||||
$cursorY = $drawHeader();
|
||||
foreach ($items as $item) {
|
||||
$sampleText = formatSampleDataForText($item['code']);
|
||||
$desc = 'Standard: ' . $item['standard'] . "\n" . 'Use: ' . $item['use'] . "\n" . 'Sample data: ' . $sampleText;
|
||||
|
||||
$descTopOffset = 4.5;
|
||||
$descLineSpace = 1.0;
|
||||
$barcodeGap = 4.0;
|
||||
$barcodeBlockGap = 8.0;
|
||||
|
||||
while (true) {
|
||||
$descTopY = $cursorY + $descTopOffset;
|
||||
$descOut = $pdf->getTextCell(
|
||||
txt: $desc,
|
||||
posx: $marginLeft,
|
||||
posy: $descTopY,
|
||||
width: $contentWidth,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: $descLineSpace,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$descBBox = $pdf->getLastBBox();
|
||||
$barcodePosY = (float) $descBBox['y'] + (float) $descBBox['h'] + $barcodeGap;
|
||||
$barcodeWidth = -1;
|
||||
$barcodeHeight = $square ? -1 : 10;
|
||||
|
||||
if (!$square) {
|
||||
$ncols = (int) $pdf->barcode->getBarcodeObj($item['type'], $item['code'])->getArray()['ncols'];
|
||||
$targetMinBarWidth = 0.65;
|
||||
$barcodeWidth = (int) \max(1, \round($ncols * $targetMinBarWidth));
|
||||
}
|
||||
|
||||
$barcodeModel = $pdf->barcode->getBarcodeObj(
|
||||
$item['type'],
|
||||
$item['code'],
|
||||
$barcodeWidth,
|
||||
$barcodeHeight,
|
||||
'black',
|
||||
[0, 0, 0, 0],
|
||||
);
|
||||
$barcodeData = $barcodeModel->getArray();
|
||||
$itemBottomY = $barcodePosY + (float) $barcodeData['full_height'];
|
||||
$nextCursorY = $itemBottomY + $barcodeBlockGap;
|
||||
|
||||
if ($nextCursorY <= $maxY) {
|
||||
break;
|
||||
}
|
||||
|
||||
$page = $pdf->addPage([
|
||||
'margin' => [
|
||||
'PL' => $marginLeft,
|
||||
'PR' => $marginRight,
|
||||
'CT' => $marginTop,
|
||||
'CB' => $marginBottom,
|
||||
],
|
||||
]);
|
||||
|
||||
$cursorY = $drawHeader();
|
||||
}
|
||||
|
||||
$pdf->page->addContent($textfont['out']);
|
||||
$head = '[' . $item['type'] . '] ' . $item['name'];
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $head,
|
||||
posx: $marginLeft,
|
||||
posy: $cursorY,
|
||||
width: $contentWidth,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($smallfont['out']);
|
||||
$pdf->page->addContent($descOut);
|
||||
|
||||
$pdf->page->addContent($pdf->getBarcode(
|
||||
type: $item['type'],
|
||||
code: $item['code'],
|
||||
posx: $marginLeft,
|
||||
posy: $barcodePosY,
|
||||
width: $barcodeWidth,
|
||||
height: $barcodeHeight,
|
||||
padding: [0, 0, 0, 0],
|
||||
style: $style,
|
||||
));
|
||||
|
||||
$cursorY = $nextCursorY;
|
||||
}
|
||||
}
|
||||
|
||||
renderBarcodeSection($pdf, $linear, 'Linear', 1, $titlefont, $textfont, $smallfont, $style, false);
|
||||
renderBarcodeSection($pdf, $square, 'Square / 2D', 2, $titlefont, $textfont, $smallfont, $style, true);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E021_font_stretch_spacing.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 021');
|
||||
$pdf->setTitle('Font stretching, scaling and spacing');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example font stretching scaling spacing');
|
||||
$pdf->setPDFFilename('021_font_stretch_spacing.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$style = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.2,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'black',
|
||||
'fillColor' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$applyFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, float $spacing, float $stretching, int $size = 11): array {
|
||||
// $stretching is a font-stack ratio (1.0 = 100%); the percent-valued modes
|
||||
// below divide by 100 before calling this helper.
|
||||
$font = $pdf->font->insert($pdf->pon, 'times', '', $size, $spacing, $stretching);
|
||||
$pdf->page->addContent($font['out']);
|
||||
return $font;
|
||||
};
|
||||
|
||||
$measureText = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $text): array {
|
||||
$ordarr = $pdf->uniconv->strToOrdArr($text);
|
||||
$width = $pdf->font->getOrdArrWidth($ordarr);
|
||||
return [$ordarr, $width];
|
||||
};
|
||||
|
||||
$drawBoxedLine = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
array $style,
|
||||
string $text,
|
||||
float $x,
|
||||
float $y,
|
||||
float $w,
|
||||
float $h,
|
||||
float $spacing,
|
||||
float $stretching,
|
||||
) use ($applyFont): void {
|
||||
$font = $applyFont($pdf, $spacing, $stretching, 11);
|
||||
$pdf->page->addContent($pdf->graph->getRect($x, $y, $w, $h, 'D', $style));
|
||||
$baseline = $y + 1.5 + $pdf->toUnit($font['ascent']);
|
||||
$pdf->page->addContent($pdf->getTextLine(txt: $text, posx: $x + 1.5, posy: $baseline));
|
||||
};
|
||||
|
||||
$setNeutralTitleFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf): void {
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 13, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
};
|
||||
|
||||
$setNeutralTextFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf): void {
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', '', 9, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
};
|
||||
|
||||
// Insert one neutral font before addPage() so page context has a valid current font.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$setNeutralTitleFont($pdf);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Example 021 - Font stretching, scaling and spacing',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$setNeutralTextFont($pdf);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'This mirrors the legacy cell stretch sample using tc-lib-pdf font spacing/stretching controls.',
|
||||
posx: 15,
|
||||
posy: 23,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$sample = 'TEST CELL STRETCH: scaling and spacing';
|
||||
$left = 15;
|
||||
$top = 32;
|
||||
$cellw = 85;
|
||||
$cellh = 8;
|
||||
$labelw = 95;
|
||||
|
||||
$applyFont($pdf, 0.0, 1.0, 11);
|
||||
[$ordarr, $baseWidthPoints] = $measureText($pdf, $sample);
|
||||
$textChars = \count($ordarr);
|
||||
$targetWidthPoints = $pdf->toPoints($cellw - 3);
|
||||
|
||||
$scaleFitRatio = $baseWidthPoints > $targetWidthPoints ? $targetWidthPoints / $baseWidthPoints : 1.0;
|
||||
$scaleForceRatio = $targetWidthPoints / $baseWidthPoints;
|
||||
$scaleFit = 100.0 * $scaleFitRatio;
|
||||
$scaleForce = 100.0 * $scaleForceRatio;
|
||||
|
||||
$spacingFit = 0.0;
|
||||
if ($baseWidthPoints > $targetWidthPoints && $textChars > 1) {
|
||||
$spacingFit = ($targetWidthPoints - $baseWidthPoints) / ($textChars - 1);
|
||||
}
|
||||
|
||||
$spacingForce = 0.0;
|
||||
if ($textChars > 1) {
|
||||
$spacingForce = ($targetWidthPoints - $baseWidthPoints) / ($textChars - 1);
|
||||
}
|
||||
|
||||
$modes = [
|
||||
['no stretch', 0.0, 100.0],
|
||||
['scaling (fit)', 0.0, $scaleFit],
|
||||
['force scaling', 0.0, $scaleForce],
|
||||
['spacing (fit)', $spacingFit, 100.0],
|
||||
['force spacing', $spacingForce, 100.0],
|
||||
];
|
||||
|
||||
$firstBlockEndY = $top;
|
||||
$row = 0;
|
||||
foreach ($modes as $mode) {
|
||||
$y = $top + ($row * ($cellh + 1.5));
|
||||
$label = \sprintf('%s [stretch=%.1f%%, spacing=%.3fpt]', $mode[0], $mode[2], $mode[1]);
|
||||
$setNeutralTextFont($pdf);
|
||||
$pdf->page->addContent($pdf->getTextLine(txt: $label, posx: $left, posy: $y + 5.5));
|
||||
$drawBoxedLine($pdf, $style, $sample, $left + $labelw, $y, $cellw, $cellh, $mode[1], $mode[2] / 100.0);
|
||||
$firstBlockEndY = \max($firstBlockEndY, $y + $cellh, $y + 6.5);
|
||||
++$row;
|
||||
}
|
||||
|
||||
$secondIntroY = $firstBlockEndY + 10.0;
|
||||
$secondTitleY = $secondIntroY + 8.0;
|
||||
$secondRowsStartY = $secondTitleY + 9.0;
|
||||
|
||||
$setNeutralTextFont($pdf);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Second section: global font stretching and spacing combinations (legacy example style).',
|
||||
posx: 15,
|
||||
posy: $secondIntroY,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$setNeutralTitleFont($pdf);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Global stretching/spacing matrix',
|
||||
posx: 15,
|
||||
posy: $secondTitleY,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$stretchVals = [90.0, 100.0, 110.0];
|
||||
$spacingVals = [-0.72, 0.0, 0.72]; // ~ -0.254, 0, +0.254 mm expressed in points.
|
||||
$sample2 = 'Stretching and spacing test text';
|
||||
|
||||
$y = $secondRowsStartY;
|
||||
foreach ($stretchVals as $stretching) {
|
||||
foreach ($spacingVals as $spacing) {
|
||||
$line = \sprintf('Stretching %3.0f%%, Spacing %+.3fpt', $stretching, $spacing);
|
||||
$setNeutralTextFont($pdf);
|
||||
$pdf->page->addContent($pdf->getTextLine(txt: $line, posx: 15, posy: $y + 5.5));
|
||||
$drawBoxedLine($pdf, $style, $sample2, 95, $y, 100, 8, $spacing, $stretching / 100.0);
|
||||
$y += 9.5;
|
||||
}
|
||||
$y += 2;
|
||||
}
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E022_cell_borders.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 022');
|
||||
$pdf->setTitle('Cell borders');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example cell borders');
|
||||
$pdf->setPDFFilename('022_cell_borders.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): array {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
return $font;
|
||||
};
|
||||
|
||||
$getLineStyle = static function (float $width, string $color): array {
|
||||
return [
|
||||
'lineWidth' => $width,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => $color,
|
||||
];
|
||||
};
|
||||
|
||||
$buildCellStyles = static function (array $sideStyles, string $fillColor): array {
|
||||
$fillStyle = [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#000000', //$fillColor,
|
||||
'fillColor' => $fillColor,
|
||||
];
|
||||
|
||||
$styles = [
|
||||
'all' => $fillStyle,
|
||||
0 => $fillStyle,
|
||||
1 => $fillStyle,
|
||||
2 => $fillStyle,
|
||||
3 => $fillStyle,
|
||||
];
|
||||
|
||||
foreach ($sideStyles as $side => $style) {
|
||||
$styles[$side] = \array_merge($fillStyle, $style, ['fillColor' => $fillColor]);
|
||||
}
|
||||
|
||||
return $styles;
|
||||
};
|
||||
|
||||
$drawStyledCell = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
string $label,
|
||||
float $x,
|
||||
float $y,
|
||||
float $w,
|
||||
float $h,
|
||||
array $styles,
|
||||
float $borderPos,
|
||||
): void {
|
||||
$pdf->setDefaultCellBorderPos(borderpos: $borderPos);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(' ', $x, $y, $w, $h, styles: $styles, drawcell: true));
|
||||
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black'));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
$label,
|
||||
$x,
|
||||
$y,
|
||||
$w,
|
||||
$h,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
drawcell: false,
|
||||
));
|
||||
};
|
||||
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 20);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Cell Borders',
|
||||
15,
|
||||
15,
|
||||
180,
|
||||
8,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 11);
|
||||
|
||||
$basicLineStyle = $getLineStyle(0.508, '#0080ff');
|
||||
$fillColor = '#ffff80';
|
||||
$maskToSide = ['T' => 0, 'R' => 1, 'B' => 2, 'L' => 3];
|
||||
|
||||
$masks = ['1', 'LTRB', 'LTR', 'TRB', 'LRB', 'LTB', 'LT', 'TR', 'RB', 'LB', 'LR', 'TB', 'L', 'T', 'R', 'B'];
|
||||
$x = 15.0;
|
||||
$y = 32.0;
|
||||
$w = 30.0;
|
||||
$h = 8.0;
|
||||
|
||||
foreach ($masks as $mask) {
|
||||
$active = $mask === '1' ? 'LTRB' : $mask;
|
||||
$sideStyles = [];
|
||||
foreach ($maskToSide as $side => $idx) {
|
||||
if (\strpos($active, $side) !== false) {
|
||||
$sideStyles[$idx] = $basicLineStyle;
|
||||
}
|
||||
}
|
||||
$drawStyledCell($pdf, $mask, $x, $y, $w, $h, $buildCellStyles($sideStyles, $fillColor), $pdf::BORDERPOS_DEFAULT);
|
||||
$y += 10.0;
|
||||
}
|
||||
|
||||
$normalBorders = [
|
||||
0 => \array_merge($getLineStyle(2.0, '#ff0000'), ['lineCap' => 'square']),
|
||||
1 => \array_merge($getLineStyle(2.0, '#ff0000'), ['lineCap' => 'square']),
|
||||
2 => \array_merge($getLineStyle(2.0, '#ff0000'), ['lineCap' => 'square']),
|
||||
3 => \array_merge($getLineStyle(2.0, '#ff0000'), ['lineCap' => 'square']),
|
||||
];
|
||||
|
||||
$multiBorders = [
|
||||
0 => \array_merge($getLineStyle(2.0, '#00ff00'), ['lineCap' => 'square']),
|
||||
1 => \array_merge($getLineStyle(2.0, '#ff00ff'), ['lineCap' => 'square']),
|
||||
2 => \array_merge($getLineStyle(2.0, '#0000ff'), ['lineCap' => 'square']),
|
||||
3 => \array_merge($getLineStyle(2.0, '#ff0000'), ['lineCap' => 'square']),
|
||||
];
|
||||
|
||||
$advX = $x;
|
||||
$advY = $y + 5.0;
|
||||
$drawStyledCell(
|
||||
$pdf,
|
||||
'LTRB',
|
||||
$advX,
|
||||
$advY,
|
||||
30,
|
||||
10,
|
||||
$buildCellStyles($normalBorders, $fillColor),
|
||||
$pdf::BORDERPOS_DEFAULT,
|
||||
);
|
||||
$advY += 15.0;
|
||||
|
||||
$drawStyledCell(
|
||||
$pdf,
|
||||
'LTRB',
|
||||
$advX,
|
||||
$advY,
|
||||
30,
|
||||
10,
|
||||
$buildCellStyles($multiBorders, $fillColor),
|
||||
$pdf::BORDERPOS_DEFAULT,
|
||||
);
|
||||
$advY += 15.0;
|
||||
|
||||
$drawStyledCell(
|
||||
$pdf,
|
||||
'LTRB EXT',
|
||||
$advX,
|
||||
$advY,
|
||||
30,
|
||||
10,
|
||||
$buildCellStyles($normalBorders, $fillColor),
|
||||
$pdf::BORDERPOS_EXTERNAL,
|
||||
);
|
||||
$advY += 15.0;
|
||||
|
||||
$drawStyledCell(
|
||||
$pdf,
|
||||
'LTRB INT',
|
||||
$advX,
|
||||
$advY,
|
||||
30,
|
||||
10,
|
||||
$buildCellStyles($normalBorders, $fillColor),
|
||||
$pdf::BORDERPOS_INTERNAL,
|
||||
);
|
||||
|
||||
$pdf->setDefaultCellBorderPos(borderpos: $pdf::BORDERPOS_DEFAULT);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E023_cell_alignment.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 023');
|
||||
$pdf->setTitle('Cell alignment');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example cell alignment');
|
||||
$pdf->setPDFFilename('023_cell_alignment.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): array {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
return $font;
|
||||
};
|
||||
|
||||
$getLineStyle = static function (float $width, string $color): array {
|
||||
return [
|
||||
'lineWidth' => $width,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => $color,
|
||||
];
|
||||
};
|
||||
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 20);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Cell Alignment Example',
|
||||
15,
|
||||
15,
|
||||
180,
|
||||
8,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
$bodyFont = $setFont($pdf, 'helvetica', '', 11);
|
||||
|
||||
$borderStyle = ['all' => $getLineStyle(0.7, '#0080ff')];
|
||||
$lineStyle = $getLineStyle(0.1, '#ff0000');
|
||||
$cellDef = [
|
||||
'margin' => ['T' => 0.0, 'R' => 0.0, 'B' => 0.0, 'L' => 0.0],
|
||||
'padding' => ['T' => 0.0, 'R' => 0.0, 'B' => 0.0, 'L' => 0.0],
|
||||
'borderpos' => 0.0,
|
||||
];
|
||||
|
||||
$cellW = 30.0;
|
||||
$cellH = $pdf->toUnit($bodyFont['size']) * 3.0;
|
||||
$startX = 15.0;
|
||||
$fontHeight = $pdf->toUnit($bodyFont['height']);
|
||||
$fontAscent = $pdf->toUnit($bodyFont['ascent']);
|
||||
$columns = [
|
||||
['prefix' => 'Top', 'cellAlign' => 'T'],
|
||||
['prefix' => 'Center', 'cellAlign' => 'C'],
|
||||
['prefix' => 'Bottom', 'cellAlign' => 'B'],
|
||||
['prefix' => 'Ascent', 'cellAlign' => 'A'],
|
||||
['prefix' => 'Baseline', 'cellAlign' => 'L'],
|
||||
['prefix' => 'Descent', 'cellAlign' => 'D'],
|
||||
];
|
||||
|
||||
$rows = [
|
||||
['lineY' => 60.0, 'suffix' => 'Center', 'textAlign' => 'C'],
|
||||
['lineY' => 90.0, 'suffix' => 'Top', 'textAlign' => 'T'],
|
||||
['lineY' => 120.0, 'suffix' => 'Bottom', 'textAlign' => 'B'],
|
||||
];
|
||||
|
||||
$getCellTopY = static function (
|
||||
float $lineY,
|
||||
float $cellH,
|
||||
string $cellAlign,
|
||||
string $textAlign,
|
||||
float $fontHeight,
|
||||
float $fontAscent,
|
||||
): float {
|
||||
return match ($cellAlign) {
|
||||
'C' => $lineY - ($cellH / 2.0),
|
||||
'B' => $lineY - $cellH,
|
||||
'A' => match ($textAlign) {
|
||||
'T' => $lineY,
|
||||
'B' => $lineY - ($cellH - $fontHeight),
|
||||
default => $lineY - (($cellH - $fontHeight) / 2.0),
|
||||
},
|
||||
'L' => match ($textAlign) {
|
||||
'T' => $lineY - $fontAscent,
|
||||
'B' => $lineY - ($cellH - ($fontHeight - $fontAscent)),
|
||||
default => $lineY - ((($cellH - $fontHeight) / 2.0) + $fontAscent),
|
||||
},
|
||||
'D' => match ($textAlign) {
|
||||
'T' => $lineY - $fontHeight,
|
||||
'B' => $lineY - $cellH,
|
||||
default => $lineY - (($cellH + $fontHeight) / 2.0),
|
||||
},
|
||||
default => $lineY,
|
||||
};
|
||||
};
|
||||
|
||||
$drawCellBorder = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
float $x,
|
||||
float $y,
|
||||
float $w,
|
||||
float $h,
|
||||
array $style,
|
||||
): string {
|
||||
return (
|
||||
$pdf->graph->getLine($x, $y, $x + $w, $y, $style)
|
||||
. $pdf->graph->getLine($x + $w, $y, $x + $w, $y + $h, $style)
|
||||
. $pdf->graph->getLine($x + $w, $y + $h, $x, $y + $h, $style)
|
||||
. $pdf->graph->getLine($x, $y + $h, $x, $y, $style)
|
||||
);
|
||||
};
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$pdf->page->addContent($pdf->graph->getLine(15, $row['lineY'], 195, $row['lineY'], $lineStyle));
|
||||
foreach ($columns as $idx => $col) {
|
||||
$x = $startX + ($idx * $cellW);
|
||||
$y = $getCellTopY($row['lineY'], $cellH, $col['cellAlign'], $row['textAlign'], $fontHeight, $fontAscent);
|
||||
$label = $col['prefix'] . '-' . $row['suffix'];
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black'));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
$label,
|
||||
$x,
|
||||
$y,
|
||||
$cellW,
|
||||
$cellH,
|
||||
valign: $row['textAlign'],
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
cell: $cellDef,
|
||||
drawcell: false,
|
||||
));
|
||||
$pdf->page->addContent($drawCellBorder($pdf, $x, $y, $cellW, $cellH, $borderStyle['all']));
|
||||
}
|
||||
}
|
||||
|
||||
$imagePath = __DIR__ . '/images/tcpdf_cell.png';
|
||||
if (\is_file($imagePath)) {
|
||||
$imgId = $pdf->image->add($imagePath);
|
||||
$page = $pdf->page->getPage($pdf->page->getPageId());
|
||||
$pdf->page->addContent($pdf->image->getSetImage($imgId, 15, 160, 100, 100, $page['height']));
|
||||
}
|
||||
|
||||
$legend =
|
||||
"LEGEND:\n\n"
|
||||
. "X: cell x top-left origin (top-right for RTL)\n"
|
||||
. "Y: cell y top-left origin (top-right for RTL)\n"
|
||||
. "CW: cell width\n"
|
||||
. "CH: cell height\n"
|
||||
. "LW: line width\n"
|
||||
. "NRL: normal line position\n"
|
||||
. "EXT: external line position\n"
|
||||
. "INT: internal line position\n"
|
||||
. "ML: margin left\n"
|
||||
. "MR: margin right\n"
|
||||
. "MT: margin top\n"
|
||||
. "MB: margin bottom\n"
|
||||
. "PL: padding left\n"
|
||||
. "PR: padding right\n"
|
||||
. "PT: padding top\n"
|
||||
. "PB: padding bottom\n"
|
||||
. "TW: text width\n"
|
||||
. "FA: font ascent\n"
|
||||
. "FB: font baseline\n"
|
||||
. 'FD: font descent';
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->page->addContent($pdf->getTextCell($legend, 125, 160, 70, 100, 0, 1.25, 'T', 'L', drawcell: false));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E024_colors.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 024');
|
||||
$pdf->setTitle('CMYK, RGB and Grayscale colors');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example cmyk rgb grayscale colors');
|
||||
$pdf->setPDFFilename('024_colors.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$fontFamily = 'helvetica';
|
||||
$fontStyle = '';
|
||||
$fontSize = 10;
|
||||
|
||||
$drawColorBlock = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
float $x,
|
||||
float $y,
|
||||
float $w,
|
||||
float $h,
|
||||
string $label,
|
||||
string $strokeColor,
|
||||
string $fillColor,
|
||||
string $textColor,
|
||||
): void {
|
||||
$style = [
|
||||
'all' => [
|
||||
'lineWidth' => 2.0,
|
||||
'lineCap' => 'square',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => $strokeColor,
|
||||
'fillColor' => $fillColor,
|
||||
],
|
||||
];
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getRect($x, $y, $w, $h, 'DF', $style));
|
||||
$pdf->page->addContent($pdf->color->getPdfColor($textColor));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
$label,
|
||||
$x,
|
||||
$y + $h + 2.0,
|
||||
$w,
|
||||
6.0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
};
|
||||
|
||||
// Insert the font once and reuse it across all pages.
|
||||
$pdf->font->insert($pdf->pon, $fontFamily, $fontStyle, $fontSize, 0.0, 1.0);
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$colorIntroHtml = '<h1>Color Example</h1>This page demonstrates core color support powered by <span style="color:#008800">tc-lib-color</span>. The library provides unified parsing and conversion for grayscale, RGB, CMYK, spot, and Lab color models so the same API can target both screen output and print-ready workflows. In this sample, color definitions are applied consistently to fills, strokes, and text to highlight how each model can be mixed in a single PDF document.';
|
||||
$pdf->addHTMLCell(html: $colorIntroHtml, posx: 15, posy: 28, width: 180);
|
||||
|
||||
$posy = 100;
|
||||
|
||||
$drawColorBlock($pdf, 30.0, $posy, 30.0, 30.0, 'Cyan', 'cmyk(50,0,0,0)', 'cmyk(100,0,0,0)', 'cmyk(100,0,0,0)');
|
||||
$drawColorBlock($pdf, 70.0, $posy, 30.0, 30.0, 'Magenta', 'cmyk(0,50,0,0)', 'cmyk(0,100,0,0)', 'cmyk(0,100,0,0)');
|
||||
$drawColorBlock($pdf, 110.0, $posy, 30.0, 30.0, 'Yellow', 'cmyk(0,0,50,0)', 'cmyk(0,0,100,0)', 'cmyk(0,0,100,0)');
|
||||
$drawColorBlock($pdf, 150.0, $posy, 30.0, 30.0, 'Black', 'cmyk(0,0,0,50)', 'cmyk(0,0,0,100)', 'cmyk(0,0,0,100)');
|
||||
|
||||
$posy += 50;
|
||||
$drawColorBlock($pdf, 30.0, $posy, 30.0, 30.0, 'Red', 'rgb(255,127,127)', 'rgb(255,0,0)', 'rgb(255,0,0)');
|
||||
$drawColorBlock($pdf, 70.0, $posy, 30.0, 30.0, 'Green', 'rgb(127,255,127)', 'rgb(0,255,0)', 'rgb(0,255,0)');
|
||||
$drawColorBlock($pdf, 110.0, $posy, 30.0, 30.0, 'Blue', 'rgb(127,127,255)', 'rgb(0,0,255)', 'rgb(0,0,255)');
|
||||
|
||||
$posy += 50;
|
||||
$drawColorBlock($pdf, 30.0, $posy, 30.0, 30.0, 'Gray', '#bfbfbf', '#7f7f7f', '#7f7f7f');
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->addPage();
|
||||
$spotIntroHtml = '<h1>Example of Spot Colors</h1>Spot colors are single, pre-mixed inks, rather than colors produced by four (CMYK), six (CMYKOG), or more process inks during printing. They are usually supplied by specialized vendors, although many printers also use in-house formulations to match target shades.<br /><br />Because there is no universal open standard for spot colors, users typically rely on vendor color books and manually register both the spot color names and their CMYK equivalents.<br /><br />Common industry spot color systems include:<br /><span style="color:#008800">ANPA-COLOR, DIC, FOCOLTONE, GCMI, HKS, PANTONE, TOYO, TRUMATCH</span>.';
|
||||
$pdf->addHTMLCell(html: $spotIntroHtml, posx: 15, posy: 28, width: 180);
|
||||
|
||||
$pdf->color->addSpotColor('My TCPDF Dark Green', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 1.0,
|
||||
'magenta' => 0.5,
|
||||
'yellow' => 0.8,
|
||||
'key' => 0.45,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('My TCPDF Light Yellow', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.0,
|
||||
'magenta' => 0.0,
|
||||
'yellow' => 0.55,
|
||||
'key' => 0.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('My TCPDF Black', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.0,
|
||||
'magenta' => 0.0,
|
||||
'yellow' => 0.0,
|
||||
'key' => 1.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('My TCPDF Red', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.3,
|
||||
'magenta' => 1.0,
|
||||
'yellow' => 0.9,
|
||||
'key' => 0.1,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('My TCPDF Green', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 1.0,
|
||||
'magenta' => 0.3,
|
||||
'yellow' => 1.0,
|
||||
'key' => 0.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('My TCPDF Blue', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 1.0,
|
||||
'magenta' => 0.6,
|
||||
'yellow' => 0.1,
|
||||
'key' => 0.05,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('My TCPDF Yellow', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.0,
|
||||
'magenta' => 0.2,
|
||||
'yellow' => 1.0,
|
||||
'key' => 0.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
|
||||
$drawSpotColorBlock = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
float $x,
|
||||
float $y,
|
||||
float $w,
|
||||
float $h,
|
||||
string $spotName,
|
||||
float $tint,
|
||||
): void {
|
||||
$pdf->page->addContent($pdf->color->getPdfColor($spotName, true, $tint));
|
||||
$pdf->page->addContent($pdf->color->getPdfColor($spotName, false, $tint));
|
||||
$pdf->page->addContent($pdf->graph->getRect($x, $y, $w, $h, 'DF'));
|
||||
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('My TCPDF Black', false, 1.0));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
$spotName,
|
||||
$x + $w + 3.0,
|
||||
$y + 6.0,
|
||||
110.0,
|
||||
8.0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
};
|
||||
|
||||
$spots = [
|
||||
'My TCPDF Dark Green',
|
||||
'My TCPDF Light Yellow',
|
||||
'My TCPDF Red',
|
||||
'My TCPDF Green',
|
||||
'My TCPDF Blue',
|
||||
'My TCPDF Yellow',
|
||||
];
|
||||
|
||||
$startY = 90.0;
|
||||
foreach ($spots as $spot) {
|
||||
$drawSpotColorBlock($pdf, 30.0, $startY, 40.0, 16.0, $spot, 1.0);
|
||||
$startY += 24.0;
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->addPage();
|
||||
$labIntroHtml = '<h1>Example of Lab Spot Colors</h1>Lab-based spot colors define color values using CIE L*a*b* coordinates, which are device-independent and better suited for consistent cross-device color reproduction.<br /><br />The following sample spot colors are registered using <span style="color:#008800">addSpotLabColor()</span> and then rendered with standard spot-color drawing commands.';
|
||||
$pdf->addHTMLCell(html: $labIntroHtml, posx: 15, posy: 28, width: 180);
|
||||
|
||||
$pdf->color->addSpotLabColor('My TCPDF Lab Red', 53.0, 80.0, 67.0);
|
||||
$pdf->color->addSpotLabColor('My TCPDF Lab Green', 87.0, -86.0, 83.0);
|
||||
$pdf->color->addSpotLabColor('My TCPDF Lab Blue', 32.0, 79.0, -108.0);
|
||||
$pdf->color->addSpotLabColor('My TCPDF Lab Orange', 74.0, 24.0, 78.0);
|
||||
$pdf->color->addSpotLabColor('My TCPDF Lab Violet', 40.0, 60.0, -55.0);
|
||||
$pdf->color->addSpotLabColor('My TCPDF Lab Gray', 55.0, 0.0, 0.0);
|
||||
|
||||
// Advanced Lab spot example: custom whitepoint/blackpoint (D50 with non-zero blackpoint).
|
||||
$pdf->color->addSpotLabColor(
|
||||
'My TCPDF Lab D50 Orange',
|
||||
64.25,
|
||||
58.5,
|
||||
71.2,
|
||||
[0.9642, 1.0000, 0.8251],
|
||||
[0.0120, 0.0125, 0.0110],
|
||||
);
|
||||
|
||||
// Advanced Lab spot example: constrained a*/b* range and explicit Tint=0 Lab endpoint (col0).
|
||||
$pdf->color->addSpotLabColor(
|
||||
'My TCPDF Lab Narrow Blue',
|
||||
36.0,
|
||||
62.0,
|
||||
-76.0,
|
||||
[0.9505, 1.0000, 1.0890],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-96.0, 96.0, -96.0, 96.0],
|
||||
[92.0, -4.0, -8.0],
|
||||
);
|
||||
|
||||
$labSpots = [
|
||||
['My TCPDF Lab Red', 1.0],
|
||||
['My TCPDF Lab Green', 1.0],
|
||||
['My TCPDF Lab Blue', 1.0],
|
||||
['My TCPDF Lab Orange', 0.9],
|
||||
['My TCPDF Lab Violet', 0.85],
|
||||
['My TCPDF Lab Gray', 1.0],
|
||||
['My TCPDF Lab D50 Orange', 1.0],
|
||||
['My TCPDF Lab Narrow Blue', 1.0],
|
||||
];
|
||||
|
||||
$startY = 70.0;
|
||||
foreach ($labSpots as [$spot, $tint]) {
|
||||
$drawSpotColorBlock($pdf, 30.0, $startY, 40.0, 16.0, $spot, $tint);
|
||||
$startY += 24.0;
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E025_transparency.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 025');
|
||||
$pdf->setTitle('Object transparency');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example object transparency alpha extgstate');
|
||||
$pdf->setPDFFilename('025_transparency.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): array {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
return $font;
|
||||
};
|
||||
|
||||
$getRectStyle = static function (string $strokeColor, string $fillColor): array {
|
||||
return [
|
||||
'all' => [
|
||||
'lineWidth' => 2.0,
|
||||
'lineCap' => 'square',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => $strokeColor,
|
||||
'fillColor' => $fillColor,
|
||||
],
|
||||
];
|
||||
};
|
||||
|
||||
// Insert one neutral font before addPage() so page context has a valid current font.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 12);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'You can set the transparency of PDF objects using graph->getAlpha().',
|
||||
15,
|
||||
20,
|
||||
180,
|
||||
0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Opaque red square.
|
||||
$pdf->page->addContent($pdf->graph->getRect(
|
||||
30.0,
|
||||
40.0,
|
||||
60.0,
|
||||
60.0,
|
||||
'DF',
|
||||
$getRectStyle('rgb(127,0,0)', 'rgb(255,0,0)'),
|
||||
));
|
||||
|
||||
// Semi-transparent objects.
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(0.5));
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getRect(
|
||||
50.0,
|
||||
60.0,
|
||||
60.0,
|
||||
60.0,
|
||||
'DF',
|
||||
$getRectStyle('rgb(0,127,0)', 'rgb(0,255,0)'),
|
||||
));
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getRect(
|
||||
70.0,
|
||||
80.0,
|
||||
60.0,
|
||||
60.0,
|
||||
'DF',
|
||||
$getRectStyle('rgb(0,0,127)', 'rgb(0,0,255)'),
|
||||
));
|
||||
|
||||
$imagePath = __DIR__ . '/images/tcpdf_logo.jpg';
|
||||
if (\is_file($imagePath)) {
|
||||
$imageId = $pdf->image->add($imagePath);
|
||||
$pdf->page->addContent($pdf->image->getSetImage($imageId, 90.0, 100.0, 60.0, 60.0, $page['height']));
|
||||
}
|
||||
|
||||
// Restore full opacity.
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(1.0));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E026_text_rendering_modes.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 026');
|
||||
$pdf->setTitle('Text rendering modes and clipping');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example text rendering mode clipping stroke fill');
|
||||
$pdf->setPDFFilename('026_text_rendering_modes.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): array {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
return $font;
|
||||
};
|
||||
|
||||
$drawTextModeLine = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
string $text,
|
||||
float $y,
|
||||
float $strokeWidth,
|
||||
bool $fill,
|
||||
bool $stroke,
|
||||
bool $clip,
|
||||
int $imageId,
|
||||
float $pageHeight,
|
||||
): void {
|
||||
if ($clip) {
|
||||
$pdf->page->addContent($pdf->graph->getStartTransform());
|
||||
}
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
$text,
|
||||
15.0,
|
||||
$y,
|
||||
180.0,
|
||||
0.0,
|
||||
strokewidth: $strokeWidth,
|
||||
fill: $fill,
|
||||
stroke: $stroke,
|
||||
clip: $clip,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
if ($clip && $imageId > 0) {
|
||||
$pdf->page->addContent($pdf->image->getSetImage($imageId, 15.0, $y + 2.0, 170.0, 10.0, $pageHeight));
|
||||
$pdf->page->addContent($pdf->graph->getStopTransform());
|
||||
}
|
||||
};
|
||||
|
||||
// Insert one neutral font before addPage() so page context has a valid current font.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
|
||||
$page = $pdf->addPage();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 11);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Text rendering modes: fill, stroke, fill+stroke, invisible, and clipping.',
|
||||
15.0,
|
||||
20.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 22);
|
||||
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black', false));
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('rgb(255,0,0)', true));
|
||||
|
||||
$drawTextModeLine($pdf, 'Fill text', 35.0, 0.0, true, false, false, 0, $page['height']);
|
||||
$drawTextModeLine($pdf, 'Stroke text', 47.0, 0.2, false, true, false, 0, $page['height']);
|
||||
$drawTextModeLine($pdf, 'Fill, then stroke text', 59.0, 0.2, true, true, false, 0, $page['height']);
|
||||
$drawTextModeLine($pdf, 'Neither fill nor stroke text (invisible)', 71.0, 0.0, false, false, false, 0, $page['height']);
|
||||
|
||||
$imagePath = __DIR__ . '/images/tcpdf_logo.jpg';
|
||||
$imageId = 0;
|
||||
if (\is_file($imagePath)) {
|
||||
$imageId = $pdf->image->add($imagePath);
|
||||
}
|
||||
|
||||
$drawTextModeLine(
|
||||
$pdf,
|
||||
'Fill text and add to path for clipping',
|
||||
95.0,
|
||||
0.0,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
$imageId,
|
||||
$page['height'],
|
||||
);
|
||||
$drawTextModeLine(
|
||||
$pdf,
|
||||
'Stroke text and add to path for clipping',
|
||||
107.0,
|
||||
0.3,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
$imageId,
|
||||
$page['height'],
|
||||
);
|
||||
$drawTextModeLine(
|
||||
$pdf,
|
||||
'Fill, then stroke text and add to path for clipping',
|
||||
119.0,
|
||||
0.3,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
$imageId,
|
||||
$page['height'],
|
||||
);
|
||||
$drawTextModeLine($pdf, 'Add text to path for clipping', 131.0, 0.0, false, false, true, $imageId, $page['height']);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,553 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E027_annotations.php
|
||||
*
|
||||
* Demonstrates all currently supported annotation subtypes.
|
||||
*
|
||||
* @since 2026-04-27
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 027');
|
||||
$pdf->setTitle('All Supported Annotation Types');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example annotation all subtypes');
|
||||
$pdf->setPDFFilename('027_annotations.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): void {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
};
|
||||
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 12, 0.0, 1.0);
|
||||
|
||||
$leftMargin = 20.0;
|
||||
$annX = 108.0;
|
||||
$annW = 40.0;
|
||||
$rowH = 10.0;
|
||||
|
||||
$convertTopToPdfCoordinates = static function (array $coords, float $pageHeight): array {
|
||||
$out = [];
|
||||
foreach ($coords as $idx => $val) {
|
||||
if (!is_numeric($val)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$num = (float) $val;
|
||||
if (($idx % 2) === 1) {
|
||||
$num = $pageHeight - $num;
|
||||
}
|
||||
|
||||
$out[] = $num;
|
||||
}
|
||||
|
||||
return $out;
|
||||
};
|
||||
|
||||
$normalizeAnnotationOptionCoordinates = static function (array $opt, float $pageHeight) use (
|
||||
$convertTopToPdfCoordinates,
|
||||
): array {
|
||||
$subtype = strtolower((string) ($opt['subtype'] ?? ''));
|
||||
|
||||
if ($subtype === 'line' && isset($opt['l']) && is_array($opt['l'])) {
|
||||
$opt['l'] = $convertTopToPdfCoordinates($opt['l'], $pageHeight);
|
||||
}
|
||||
|
||||
if (in_array($subtype, ['polygon', 'polyline'], true) && isset($opt['vertices']) && is_array($opt['vertices'])) {
|
||||
$opt['vertices'] = $convertTopToPdfCoordinates($opt['vertices'], $pageHeight);
|
||||
}
|
||||
|
||||
if (in_array($subtype, ['highlight', 'underline', 'squiggly', 'strikeout', 'redact'], true)) {
|
||||
if (isset($opt['quadpoints']) && is_array($opt['quadpoints'])) {
|
||||
$quadOut = [];
|
||||
foreach ($opt['quadpoints'] as $quad) {
|
||||
if (!is_array($quad)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$quadOut[] = $convertTopToPdfCoordinates($quad, $pageHeight);
|
||||
}
|
||||
|
||||
$opt['quadpoints'] = $quadOut;
|
||||
}
|
||||
}
|
||||
|
||||
if ($subtype === 'ink' && isset($opt['inklist']) && is_array($opt['inklist'])) {
|
||||
$inkOut = [];
|
||||
foreach ($opt['inklist'] as $line) {
|
||||
if (!is_array($line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$inkOut[] = $convertTopToPdfCoordinates($line, $pageHeight);
|
||||
}
|
||||
|
||||
$opt['inklist'] = $inkOut;
|
||||
}
|
||||
|
||||
return $opt;
|
||||
};
|
||||
|
||||
$addRow = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
string $label,
|
||||
float $y,
|
||||
string $txt,
|
||||
array $opt,
|
||||
float $pageHeight,
|
||||
string $preview = '',
|
||||
) use ($leftMargin, $annX, $annW, $rowH, $normalizeAnnotationOptionCoordinates): int {
|
||||
$x = $leftMargin;
|
||||
$labelW = $annX - $x - 1.0;
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
$label,
|
||||
$x,
|
||||
$y,
|
||||
$labelW,
|
||||
$rowH,
|
||||
drawcell: true,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'',
|
||||
$annX,
|
||||
$y,
|
||||
$annW,
|
||||
$rowH,
|
||||
drawcell: true,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
if ($preview !== '') {
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
$preview,
|
||||
$annX + 0.4,
|
||||
$y + 0.3,
|
||||
$annW - 0.8,
|
||||
$rowH - 0.6,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
}
|
||||
|
||||
$aid = $pdf->setAnnotation(
|
||||
posx: $annX,
|
||||
posy: $y,
|
||||
width: $annW,
|
||||
height: $rowH,
|
||||
txt: $txt,
|
||||
opt: $normalizeAnnotationOptionCoordinates($opt, $pageHeight),
|
||||
);
|
||||
$pdf->page->addAnnotRef($aid);
|
||||
|
||||
return $aid;
|
||||
};
|
||||
|
||||
$mkQuadPoints = static function (float $x, float $y, float $w, float $h): array {
|
||||
return [[
|
||||
$x,
|
||||
$y + $h,
|
||||
$x + $w,
|
||||
$y + $h,
|
||||
$x,
|
||||
$y,
|
||||
$x + $w,
|
||||
$y,
|
||||
]];
|
||||
};
|
||||
|
||||
$attachmentPath = __DIR__ . '/data/utf8test.txt';
|
||||
$soundPath = __DIR__ . '/data/utf8test.txt';
|
||||
|
||||
$page1 = $pdf->addPage();
|
||||
$setFont($pdf, 'helvetica', 'B', 16);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'All Supported Annotation Types (page 1/2)',
|
||||
$leftMargin,
|
||||
10,
|
||||
190,
|
||||
9,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$y = 22.0;
|
||||
$textAnnotId = $addRow(
|
||||
$pdf,
|
||||
'Text',
|
||||
$y,
|
||||
"Text note body\nwith two lines",
|
||||
['subtype' => 'Text', 'name' => 'Comment', 't' => 'Text note'],
|
||||
$page1['height'],
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Link (URI)',
|
||||
$y,
|
||||
'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
['subtype' => 'Link', 'h' => 'I'],
|
||||
$page1['height'],
|
||||
'Open URL',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'FreeText',
|
||||
$y,
|
||||
'FreeText content',
|
||||
['subtype' => 'FreeText', 'da' => '/F1 10 Tf', 'q' => 1, 'it' => 'FreeTextTypeWriter'],
|
||||
$page1['height'],
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Line',
|
||||
$y,
|
||||
'Line annotation',
|
||||
[
|
||||
'subtype' => 'Line',
|
||||
'l' => [$annX + 1.0, $y + ($rowH - 1.0), $annX + $annW - 1.0, $y + 1.0],
|
||||
'le' => ['OpenArrow', 'ClosedArrow'],
|
||||
'cap' => true,
|
||||
'it' => 'LineDimension',
|
||||
],
|
||||
$page1['height'],
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow($pdf, 'Square', $y, 'Square annotation', ['subtype' => 'Square', 'ic' => [0.9, 0.9, 0.5]], $page1['height']);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow($pdf, 'Circle', $y, 'Circle annotation', ['subtype' => 'Circle', 'ic' => [0.7, 0.9, 1.0]], $page1['height']);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Polygon',
|
||||
$y,
|
||||
'Polygon annotation',
|
||||
[
|
||||
'subtype' => 'Polygon',
|
||||
'vertices' => [
|
||||
$annX,
|
||||
$y + ($rowH - 2.0),
|
||||
$annX + 14.0,
|
||||
$y + 1.5,
|
||||
$annX + 28.0,
|
||||
$y + ($rowH - 2.0),
|
||||
$annX + $annW,
|
||||
$y + 1.5,
|
||||
],
|
||||
],
|
||||
$page1['height'],
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Polyline',
|
||||
$y,
|
||||
'Polyline annotation',
|
||||
[
|
||||
'subtype' => 'Polyline',
|
||||
'vertices' => [
|
||||
$annX,
|
||||
$y + 1.5,
|
||||
$annX + 12.0,
|
||||
$y + ($rowH - 2.0),
|
||||
$annX + 24.0,
|
||||
$y + 1.5,
|
||||
$annX + $annW,
|
||||
$y + ($rowH - 2.0),
|
||||
],
|
||||
'le' => ['Circle', 'Slash'],
|
||||
],
|
||||
$page1['height'],
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$qp1 = $mkQuadPoints($annX, $y, $annW, $rowH);
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Highlight',
|
||||
$y,
|
||||
'Highlight annotation',
|
||||
['subtype' => 'Highlight', 'quadpoints' => $qp1],
|
||||
$page1['height'],
|
||||
'Sample text',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$qp2 = $mkQuadPoints($annX, $y, $annW, $rowH);
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Underline',
|
||||
$y,
|
||||
'Underline annotation',
|
||||
['subtype' => 'Underline', 'quadpoints' => $qp2],
|
||||
$page1['height'],
|
||||
'Sample text',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$qp3 = $mkQuadPoints($annX, $y, $annW, $rowH);
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Squiggly',
|
||||
$y,
|
||||
'Squiggly annotation',
|
||||
['subtype' => 'Squiggly', 'quadpoints' => $qp3],
|
||||
$page1['height'],
|
||||
'Sample text',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$qp4 = $mkQuadPoints($annX, $y, $annW, $rowH);
|
||||
$addRow(
|
||||
$pdf,
|
||||
'StrikeOut',
|
||||
$y,
|
||||
'StrikeOut annotation',
|
||||
['subtype' => 'StrikeOut', 'quadpoints' => $qp4],
|
||||
$page1['height'],
|
||||
'Sample text',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow($pdf, 'Stamp', $y, 'Stamp annotation', ['subtype' => 'Stamp', 'name' => 'Approved'], $page1['height']);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow($pdf, 'Caret', $y, 'Caret annotation', ['subtype' => 'Caret', 'sy' => 'P'], $page1['height']);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Ink',
|
||||
$y,
|
||||
'Ink annotation',
|
||||
[
|
||||
'subtype' => 'Ink',
|
||||
'inklist' => [[
|
||||
$annX,
|
||||
$y + ($rowH - 2.0),
|
||||
$annX + 14.0,
|
||||
$y + 2.0,
|
||||
$annX + 28.0,
|
||||
$y + ($rowH - 2.0),
|
||||
$annX + $annW,
|
||||
$y + 2.5,
|
||||
]],
|
||||
],
|
||||
$page1['height'],
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Popup (parent: Text)',
|
||||
$y,
|
||||
'Popup annotation',
|
||||
['subtype' => 'Popup', 'parent' => ['n' => $textAnnotId], 'open' => false],
|
||||
$page1['height'],
|
||||
'Popup target',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
if (is_file($attachmentPath)) {
|
||||
$addRow(
|
||||
$pdf,
|
||||
'FileAttachment',
|
||||
$y,
|
||||
'Attached file',
|
||||
['subtype' => 'FileAttachment', 'name' => 'PushPin', 'fs' => $attachmentPath],
|
||||
$page1['height'],
|
||||
);
|
||||
} else {
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'FileAttachment skipped: missing examples/data/utf8test.txt',
|
||||
posx: $leftMargin,
|
||||
posy: $y,
|
||||
width: 190,
|
||||
height: 7,
|
||||
));
|
||||
}
|
||||
|
||||
$page2 = $pdf->addPage();
|
||||
$setFont($pdf, 'helvetica', 'B', 16);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'All Supported Annotation Types (page 2/2)',
|
||||
$leftMargin,
|
||||
10,
|
||||
190,
|
||||
9,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$y = 22.0;
|
||||
|
||||
if (is_file($soundPath)) {
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Sound',
|
||||
$y,
|
||||
'Sound payload',
|
||||
['subtype' => 'Sound', 'name' => 'Speaker', 'fs' => $soundPath],
|
||||
$page2['height'],
|
||||
'Sound icon',
|
||||
);
|
||||
} else {
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Sound skipped: missing examples/data/utf8test.txt',
|
||||
posx: $leftMargin,
|
||||
posy: $y,
|
||||
width: 190,
|
||||
height: 7,
|
||||
));
|
||||
}
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Movie',
|
||||
$y,
|
||||
'Movie payload',
|
||||
[
|
||||
'subtype' => 'Movie',
|
||||
't' => 'Movie title',
|
||||
'movie' => ['f' => 'sample.mov', 'aspect' => [16.0, 9.0], 'poster' => true],
|
||||
'a' => ['showcontrols' => true, 'mode' => 'Repeat'],
|
||||
],
|
||||
$page2['height'],
|
||||
'Movie action',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Screen',
|
||||
$y,
|
||||
'Screen payload',
|
||||
[
|
||||
'subtype' => 'Screen',
|
||||
't' => 'Screen title',
|
||||
'mk' => ['r' => 90, 'bc' => [0.1, 0.2, 0.3], 'tp' => 2],
|
||||
'a' => '/S /Named /N /NextPage',
|
||||
],
|
||||
$page2['height'],
|
||||
'Screen action',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Widget',
|
||||
$y,
|
||||
'field-demo',
|
||||
[
|
||||
'subtype' => 'Widget',
|
||||
'h' => 'N',
|
||||
't' => 'demo_widget',
|
||||
'v' => 'abc',
|
||||
'da' => '/F1 10 Tf',
|
||||
'q' => 0,
|
||||
],
|
||||
$page2['height'],
|
||||
'Widget field',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$redactQuad = $mkQuadPoints($annX, $y, $annW, $rowH);
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Redact',
|
||||
$y,
|
||||
'Redact payload',
|
||||
[
|
||||
'subtype' => 'Redact',
|
||||
'quadpoints' => $redactQuad,
|
||||
'overlaytext' => 'REDACTED',
|
||||
'repeat' => true,
|
||||
'da' => '/F1 10 Tf',
|
||||
'q' => 1,
|
||||
],
|
||||
$page2['height'],
|
||||
'Sample text',
|
||||
);
|
||||
$y += 10.0;
|
||||
|
||||
$addRow(
|
||||
$pdf,
|
||||
'Watermark',
|
||||
$y,
|
||||
'Watermark payload',
|
||||
[
|
||||
'subtype' => 'Watermark',
|
||||
'fixedprint' => [
|
||||
'type' => 'FixedPrint',
|
||||
'matrix' => [1.0, 0.0, 0.0, 1.0, 5.0, 5.0],
|
||||
'h' => 0.5,
|
||||
'v' => 0.5,
|
||||
],
|
||||
],
|
||||
$page2['height'],
|
||||
);
|
||||
$y += 12.0;
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Notes: PrinterMark, TrapNet, and 3D are currently intentionally unsupported and are not included in this demo.',
|
||||
$leftMargin,
|
||||
$y,
|
||||
190,
|
||||
0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E028_text_hyphenation.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 028');
|
||||
$pdf->setTitle('Text hyphenation with soft hyphens');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example text hyphenation soft hyphen shy html');
|
||||
$pdf->setPDFFilename('028_text_hyphenation.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): void {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
};
|
||||
|
||||
// Insert one neutral font before addPage() so page context has a valid current font.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 20);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Example of Text Hyphenation',
|
||||
15.0,
|
||||
22.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'The text below uses explicit soft hyphens (­) inside words and is rendered in a narrow left-aligned column.',
|
||||
15.0,
|
||||
34.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$setFont($pdf, 'times', '', 10);
|
||||
|
||||
$html =
|
||||
'<div style="color:#003f7f;text-align:justify">'
|
||||
. 'On the other hand, we de­nounce with righ­teous in­dig­na­tion '
|
||||
. 'and dis­like men who are so be­guiled and de­mo­r­al­ized by the charms '
|
||||
. 'of plea­sure of the mo­ment, so blind­ed by de­sire, that they can­not fore­see '
|
||||
. 'the pain and trou­ble that are bound to en­sue; and equal blame be­longs to '
|
||||
. 'those who fail in their du­ty through weak­ness of will, which is the same as '
|
||||
. 'say­ing through shrink­ing from toil and pain. Th­ese cas­es are per­fect­ly '
|
||||
. 'sim­ple and easy to distin­guish. In a free hour, when our pow­er of choice is '
|
||||
. 'un­tram­melled and when noth­ing pre­vents our be­ing able to do what we like '
|
||||
. 'best, ev­ery plea­sure is to be wel­comed and ev­ery pain avoid­ed. But in '
|
||||
. 'cer­tain cir­cum­s­tances and ow­ing to the claims of du­ty or the obli­ga­tions '
|
||||
. 'of busi­ness it will fre­quent­ly oc­cur that plea­sures have to be '
|
||||
. 're­pu­di­at­ed and an­noy­ances ac­cept­ed. The wise man there­fore al­ways holds '
|
||||
. 'in th­ese mat­ters to this prin­ci­ple of se­lec­tion: he re­jects plea­sures to '
|
||||
. 'se­cure other greater plea­sures, or else he en­dures pains to avoid worse pains.'
|
||||
. '</div>';
|
||||
|
||||
$cellBorderStyles = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.2,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'red',
|
||||
'fillColor' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15.0, posy: 45.0, width: 42.0, height: 0.0, cell: null, styles: $cellBorderStyles);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E029_xobject_template.php
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 029');
|
||||
$pdf->setTitle('XObject template');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example xobject template transparency clipping');
|
||||
$pdf->setPDFFilename('029_xobject_template.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): array {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, 0.0, 1.0);
|
||||
$pdf->page->addContent($font['out']);
|
||||
return $font;
|
||||
};
|
||||
|
||||
// Insert one neutral font before addPage() so page context has a valid current font.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 20);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'XObject Templates',
|
||||
15.0,
|
||||
22.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'The same template object is rendered multiple times with different sizes and alpha values.',
|
||||
15.0,
|
||||
34.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$templateWidth = 60.0;
|
||||
$templateHeight = 60.0;
|
||||
$templateGroup = ['CS' => 'DeviceRGB', 'I' => true, 'K' => false];
|
||||
$templateId = $pdf->newXObjectTemplate($templateWidth, $templateHeight, $templateGroup);
|
||||
|
||||
$imageId = 0;
|
||||
$imagePath = __DIR__ . '/images/tcpdf_logo.jpg';
|
||||
if (\is_file($imagePath)) {
|
||||
$imageId = $pdf->image->add($imagePath);
|
||||
$pdf->addXObjectImageID($templateId, $imageId);
|
||||
}
|
||||
|
||||
$templateContent = $pdf->graph->getStartTransform();
|
||||
$templateContent .= $pdf->graph->getStarPolygon(30.0, 30.0, 29.0, 10, 3, 0.0, 'CNZ');
|
||||
if ($imageId > 0) {
|
||||
$templateContent .= $pdf->image->getSetImage($imageId, 0.0, 0.0, $templateWidth, $templateHeight, $templateHeight);
|
||||
}
|
||||
$templateContent .= $pdf->graph->getStopTransform();
|
||||
|
||||
$templateFont = $pdf->font->insert($pdf->pon, 'times', 'B', 15, 0.0, 1.0);
|
||||
$pdf->addXObjectFontID($templateId, $templateFont['key']);
|
||||
$templateContent .= $templateFont['out'];
|
||||
$templateContent .= $pdf->color->getPdfColor('rgb(255,0,0)', true);
|
||||
$templateContent .= $pdf->getTextCell(
|
||||
'Template',
|
||||
0.0,
|
||||
22.0,
|
||||
$templateWidth,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
);
|
||||
|
||||
$pdf->addXObjectContent($templateId, $templateContent);
|
||||
$pdf->exitXObjectTemplate();
|
||||
|
||||
$instances = [
|
||||
[0.4, 15.0, 50.0, 20.0],
|
||||
[0.6, 27.0, 62.0, 40.0],
|
||||
[0.8, 55.0, 85.0, 60.0],
|
||||
[1.0, 95.0, 125.0, 80.0],
|
||||
];
|
||||
|
||||
foreach ($instances as [$alpha, $x, $y, $size]) {
|
||||
$pdf->page->addContent($pdf->graph->getAlpha((float) $alpha));
|
||||
$pdf->page->addContent($pdf->getXObjectTemplate($templateId, (float) $x, (float) $y, (float) $size, (float) $size));
|
||||
}
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(1.0));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,518 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E030_svg.php
|
||||
*
|
||||
* Dedicated SVG rendering example.
|
||||
*
|
||||
* Exercises all SVG image files shipped in the examples/images/ directory and
|
||||
* serves as a visual regression baseline for SVG feature development.
|
||||
*
|
||||
* @since 2026-04-26
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example_svg.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SVG directory
|
||||
$svgdir = __DIR__ . '/images';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PDF object
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 030 — SVG');
|
||||
$pdf->setTitle('SVG Rendering Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf SVG example');
|
||||
$pdf->setPDFFilename('030_svg.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// Insert a font for page labels
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page 1 — tcpdf_box.svg
|
||||
//
|
||||
// A multi-path box illustration that exercises fill, stroke, fill-rule and
|
||||
// transform handling.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'tcpdf_box.svg', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'blue');
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// Label
|
||||
$pdf->addTextCell(
|
||||
txt: 'tcpdf_box.svg — paths, fill, stroke, fill-rule',
|
||||
pid: -1,
|
||||
posx: 10,
|
||||
posy: 10,
|
||||
width: 190,
|
||||
height: 6,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
// Render at two different sizes to check scaling
|
||||
$svg01a = $pdf->addSVG(
|
||||
img: $svgdir . '/tcpdf_box.svg',
|
||||
posx: 10,
|
||||
posy: 20,
|
||||
width: 180,
|
||||
height: 120,
|
||||
pageheight: $page01['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg01a));
|
||||
|
||||
$svg01b = $pdf->addSVG(
|
||||
img: $svgdir . '/tcpdf_box.svg',
|
||||
posx: 10,
|
||||
posy: 148,
|
||||
width: 90,
|
||||
height: 60,
|
||||
pageheight: $page01['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg01b));
|
||||
|
||||
$svg01c = $pdf->addSVG(
|
||||
img: $svgdir . '/tcpdf_box.svg',
|
||||
posx: 105,
|
||||
posy: 148,
|
||||
width: 45,
|
||||
height: 30,
|
||||
pageheight: $page01['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg01c));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page 2 — testsvg.svg
|
||||
//
|
||||
// Exercises linear and radial gradients, clip-paths, complex paths, text and
|
||||
// image embedding inside an SVG document.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$page02 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'testsvg.svg', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'green');
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: 'testsvg.svg — gradients, clip-paths, text, embedded image',
|
||||
pid: -1,
|
||||
posx: 10,
|
||||
posy: 10,
|
||||
width: 190,
|
||||
height: 6,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
// Full-width render
|
||||
$svg02a = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvg.svg',
|
||||
posx: 10,
|
||||
posy: 20,
|
||||
width: 190,
|
||||
height: 95,
|
||||
pageheight: $page02['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg02a));
|
||||
|
||||
// Smaller render to verify scaling
|
||||
$svg02b = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvg.svg',
|
||||
posx: 10,
|
||||
posy: 120,
|
||||
width: 95,
|
||||
height: 47,
|
||||
pageheight: $page02['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg02b));
|
||||
|
||||
$svg02c = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvg.svg',
|
||||
posx: 110,
|
||||
posy: 120,
|
||||
width: 47,
|
||||
height: 23,
|
||||
pageheight: $page02['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg02c));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page 3 — testsvgblend.svg
|
||||
//
|
||||
// Exercises mix-blend-mode (multiply, screen, darken …) and opacity.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$page03 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'testsvgblend.svg', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'red');
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: 'testsvgblend.svg — blend modes, opacity',
|
||||
pid: -1,
|
||||
posx: 10,
|
||||
posy: 10,
|
||||
width: 190,
|
||||
height: 6,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
$svg03a = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvgblend.svg',
|
||||
posx: 10,
|
||||
posy: 20,
|
||||
width: 190,
|
||||
height: 127,
|
||||
pageheight: $page03['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg03a));
|
||||
|
||||
// Side-by-side scaled copies
|
||||
$svg03b = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvgblend.svg',
|
||||
posx: 10,
|
||||
posy: 155,
|
||||
width: 90,
|
||||
height: 60,
|
||||
pageheight: $page03['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg03b));
|
||||
|
||||
$svg03c = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvgblend.svg',
|
||||
posx: 105,
|
||||
posy: 155,
|
||||
width: 90,
|
||||
height: 60,
|
||||
pageheight: $page03['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg03c));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page 4 — tux.svg
|
||||
//
|
||||
// The Tux penguin — a complex multi-path SVG with fine detail and many style
|
||||
// attributes (fill, stroke, stroke-width, opacity).
|
||||
//
|
||||
// Copyright: Larry Ewing — permits any use with proper attribution.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$page04 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'tux.svg', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'black');
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: 'tux.svg — complex multi-path illustration (The copyright holder of the Tux image is Larry Ewing)',
|
||||
pid: -1,
|
||||
posx: 10,
|
||||
posy: 10,
|
||||
width: 190,
|
||||
height: 6,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
// Large centred render
|
||||
$svg04a = $pdf->addSVG(
|
||||
img: $svgdir . '/tux.svg',
|
||||
posx: 55,
|
||||
posy: 20,
|
||||
width: 100,
|
||||
height: 121,
|
||||
pageheight: $page04['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg04a));
|
||||
|
||||
// Three scaled thumbnails
|
||||
$svg04b = $pdf->addSVG(
|
||||
img: $svgdir . '/tux.svg',
|
||||
posx: 10,
|
||||
posy: 148,
|
||||
width: 55,
|
||||
height: 66,
|
||||
pageheight: $page04['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg04b));
|
||||
|
||||
$svg04c = $pdf->addSVG(
|
||||
img: $svgdir . '/tux.svg',
|
||||
posx: 70,
|
||||
posy: 148,
|
||||
width: 40,
|
||||
height: 48,
|
||||
pageheight: $page04['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg04c));
|
||||
|
||||
$svg04d = $pdf->addSVG(
|
||||
img: $svgdir . '/tux.svg',
|
||||
posx: 115,
|
||||
posy: 148,
|
||||
width: 25,
|
||||
height: 30,
|
||||
pageheight: $page04['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg04d));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page 5 — all four images together (overview grid)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$page05 = $pdf->addPage();
|
||||
$pdf->setBookmark(
|
||||
name: 'SVG overview grid',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: 'purple',
|
||||
);
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: 'SVG overview grid — all four images at equal size',
|
||||
pid: -1,
|
||||
posx: 10,
|
||||
posy: 10,
|
||||
width: 190,
|
||||
height: 6,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
// Row 1
|
||||
$s1 = $pdf->addSVG(
|
||||
img: $svgdir . '/tcpdf_box.svg',
|
||||
posx: 10,
|
||||
posy: 20,
|
||||
width: 90,
|
||||
height: 60,
|
||||
pageheight: $page05['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $s1));
|
||||
|
||||
$s2 = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvg.svg',
|
||||
posx: 105,
|
||||
posy: 20,
|
||||
width: 90,
|
||||
height: 60,
|
||||
pageheight: $page05['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $s2));
|
||||
|
||||
// Row 2
|
||||
$s3 = $pdf->addSVG(
|
||||
img: $svgdir . '/testsvgblend.svg',
|
||||
posx: 10,
|
||||
posy: 88,
|
||||
width: 90,
|
||||
height: 60,
|
||||
pageheight: $page05['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $s3));
|
||||
|
||||
$s4 = $pdf->addSVG(
|
||||
img: $svgdir . '/tux.svg',
|
||||
posx: 105,
|
||||
posy: 88,
|
||||
width: 90,
|
||||
height: 109,
|
||||
pageheight: $page05['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $s4));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page 6 — abstract_a4_features.svg (full-page portrait)
|
||||
//
|
||||
// Dedicated A4 portrait abstract composition that concentrates most SVG
|
||||
// features currently supported by this library in one single visual sample.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$page06 = $pdf->addPage();
|
||||
$pdf->setBookmark(
|
||||
name: 'abstract_a4_features.svg',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: 'orange',
|
||||
);
|
||||
|
||||
$svg06a = $pdf->addSVG(
|
||||
img: $svgdir . '/abstract_a4_features.svg',
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
width: $page06['width'],
|
||||
height: $page06['height'],
|
||||
pageheight: $page06['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg06a));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page 7 — path_text_regressions.svg (full-page portrait)
|
||||
//
|
||||
// Visual regression sheet for the path and text parsing rules that are easy to
|
||||
// break: numbers with no leading digit, packed decimals, scientific notation,
|
||||
// elliptical arc flags packed against their neighbours, the smooth curve
|
||||
// commands 'S' and 'T', compound subpaths under both fill rules, text
|
||||
// anchoring, XML white space handling and multi chunk text layout.
|
||||
//
|
||||
// Every shape is drawn twice, as a pale fill from a verbose path and as a dark
|
||||
// outline from the compact equivalent: the outline must trace the fill exactly.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$page07 = $pdf->addPage();
|
||||
$pdf->setBookmark(
|
||||
name: 'path_text_regressions.svg',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: 'purple',
|
||||
);
|
||||
|
||||
$svg07a = $pdf->addSVG(
|
||||
img: $svgdir . '/path_text_regressions.svg',
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
width: $page07['width'],
|
||||
height: $page07['height'],
|
||||
pageheight: $page07['height'],
|
||||
);
|
||||
$pdf->page->addContent($pdf->getSetSVG(soid: $svg07a));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Output
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,721 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E031_html_features.php
|
||||
*
|
||||
* @since 2026-04-27
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 031');
|
||||
$pdf->setTitle('HTML Features Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example HTML selectors forms table tags');
|
||||
$pdf->setPDFFilename('031_html_features.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(
|
||||
name: 'HTML feature showcase',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: '',
|
||||
);
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// NOTE:
|
||||
// The HTML parser expects input already cleaned to XHTML-like markup (e.g. via tidyHTML),
|
||||
// and attribute extraction is intentionally based on double-quoted values.
|
||||
// Unsupported interactive selectors intentionally remain no-op (for example :hover).
|
||||
// For table-structure tags, this example demonstrates current support for
|
||||
// caption/colgroup/col/tfoot; unsupported styling on colgroup/col remains
|
||||
// intentionally a no-op in this conservative implementation.
|
||||
|
||||
$html = <<<HTML
|
||||
<style>
|
||||
.demo {
|
||||
font-size: 10pt;
|
||||
color: #222222;
|
||||
}
|
||||
.demo h2 {
|
||||
color: #003366;
|
||||
margin: 0 0 3mm 0;
|
||||
}
|
||||
.demo .selector-list li:first-child {
|
||||
color: #0b6e4f;
|
||||
font-weight: bold;
|
||||
}
|
||||
.demo .selector-list li:last-child {
|
||||
color: #8a1c7c;
|
||||
}
|
||||
.demo .selector-list li:nth-child(2n+1) {
|
||||
background-color: #f4f7ff;
|
||||
}
|
||||
.demo .selector-list li:nth-child(-n+2) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.demo .group > p + a.target {
|
||||
color: #0066cc;
|
||||
}
|
||||
.demo .group > p ~ a.target {
|
||||
font-weight: bold;
|
||||
}
|
||||
.demo .generated::before {
|
||||
content: "[PRE] ";
|
||||
color: #b03030;
|
||||
}
|
||||
.demo .generated::after {
|
||||
content: " [POST]";
|
||||
font-weight: bold;
|
||||
}
|
||||
.demo p:empty {
|
||||
background-color: #fff2cc;
|
||||
border: 0.2mm solid #c7a600;
|
||||
height: 4mm;
|
||||
}
|
||||
.demo a:link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.demo table {
|
||||
border: 0.2mm solid #666666;
|
||||
}
|
||||
.demo th {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
.demo input,
|
||||
.demo select,
|
||||
.demo textarea {
|
||||
border: 0.2mm solid #777777;
|
||||
}
|
||||
.note {
|
||||
font-size: 8pt;
|
||||
color: #555555;
|
||||
}
|
||||
</style>
|
||||
<div class="demo">
|
||||
<h2>HTML Feature Showcase</h2>
|
||||
<p>This example demonstrates currently implemented selector, table, and form behavior in the HTML engine.</p>
|
||||
|
||||
<h3>1) Pseudo-class selectors</h3>
|
||||
<ul class="selector-list">
|
||||
<li>First item (first-child + odd + -n+2)</li>
|
||||
<li>Second item (-n+2)</li>
|
||||
<li>Third item (odd)</li>
|
||||
<li>Fourth item (last-child)</li>
|
||||
</ul>
|
||||
|
||||
<h3>2) Combinators (+ and ~)</h3>
|
||||
<div class="group">
|
||||
<p>Adjacent sibling trigger paragraph</p>
|
||||
<a class="target" href="https://github.com/tecnickcom/tc-lib-pdf">Adjacent + general sibling target link</a>
|
||||
</div>
|
||||
|
||||
<h3>3) Empty pseudo-class</h3>
|
||||
<p></p>
|
||||
|
||||
<h3>4) Pseudo-elements (::before / ::after, text-only content)</h3>
|
||||
<p><span class="generated">Generated marker sample</span></p>
|
||||
|
||||
<h3>5) Stable table rendering with selectors applied</h3>
|
||||
<table border="1" cellpadding="2" cellspacing="0" style="width:100%">
|
||||
<tr>
|
||||
<th style="width:20%">Key</th>
|
||||
<th style="width:80%">Value</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>first-child</td>
|
||||
<td>Supported</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>last-child</td>
|
||||
<td>Supported</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>nth-child</td>
|
||||
<td>Supports n, odd/even, and an+b (for example 2n+1, -n+2)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>empty</td>
|
||||
<td>Supported</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>link</td>
|
||||
<td>Supported for anchors with href</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>6) Table structure tags (caption, colgroup, col, tfoot)</h3>
|
||||
<table border="1" cellpadding="2" cellspacing="0" style="width:100%">
|
||||
<caption>Quarterly feature status</caption>
|
||||
<colgroup>
|
||||
<col width="22%">
|
||||
<col span="2" width="78%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Area</th>
|
||||
<th>State</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>caption</td>
|
||||
<td>Rendered</td>
|
||||
<td>Displayed as a block-level table title.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>colgroup/col width hints</td>
|
||||
<td>Applied</td>
|
||||
<td>Used as precomputed column width hints before first-row fallback.</td>
|
||||
</tr>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td>tfoot</td>
|
||||
<td>Parsed</td>
|
||||
<td>Footer row contributes to table row/column bookkeeping.</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<h3>7) Form semantics (labels, field flags, select precedence)</h3>
|
||||
<p>
|
||||
<label for="contact_email">Email (for-id label):</label>
|
||||
<input type="email" id="contact_email" name="contact_email" value="user@example.com" maxlength="64" width="150">
|
||||
</p>
|
||||
<p>
|
||||
<label>Phone (wrapping label fallback):
|
||||
<input type="text" name="contact_phone" value="+39 010 123 456" size="70" width="150">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="priority_pick">Priority:</label>
|
||||
<select id="priority_pick" name="priority_pick" value="normal" width="200">
|
||||
<optgroup label="Standard">
|
||||
<option value="normal">Normal</option>
|
||||
<option value="low">Low</option>
|
||||
</optgroup>
|
||||
<optgroup label="Urgent">
|
||||
<option value="high" selected>High (explicit selected wins)</option>
|
||||
<option value="critical">Critical</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="notes">Notes (disabled textarea mapping):</label>
|
||||
<textarea id="notes" name="notes" cols="32" rows="2" maxlength="120" disabled>Handled by support queue</textarea>
|
||||
<br>
|
||||
<span class="note">Visible fallback text: Handled by support queue</span>
|
||||
</p>
|
||||
|
||||
<p class="note">
|
||||
Unsupported selector examples intentionally remain unmatched: :hover, :focus, :active, and :visited.
|
||||
</p>
|
||||
<p class="note">
|
||||
Pseudo-elements are intentionally limited to text-only `content:"..."` behavior in this conservative implementation.
|
||||
</p>
|
||||
<p class="note">
|
||||
Unsupported styling on structural tags like colgroup/col is intentionally ignored in this conservative HTML engine pass.
|
||||
</p>
|
||||
<p class="note">
|
||||
This form section is focused on parser/field-mapping behavior; it is not intended to replicate browser form UX.
|
||||
</p>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML B
|
||||
|
||||
$pageV02 = $pdf->addPage();
|
||||
|
||||
$rect = $pdf->graph->getRect(160, 36, 30, 50, 'DF');
|
||||
$pdf->page->addContent($rect);
|
||||
|
||||
$textcolors = '<h2>Text</h1>';
|
||||
$bgcolors = '<h2>Background</h2>';
|
||||
$csscolortypes =
|
||||
'<h2>CSS Color Types</h2>'
|
||||
. '<table border="1" cellpadding="3" cellspacing="2" style="width:100%; font-size:9pt;">'
|
||||
. '<tr><th style="width:20%">Type</th><th style="width:80%">Example</th></tr>'
|
||||
. '<tr><td>named</td><td style="background-color: navy; color: #ffffff;">background-color: navy</td></tr>'
|
||||
. '<tr><td>gray</td><td style="background-color: g(50%); color: #ffffff;">background-color: g(50%)</td></tr>'
|
||||
. '<tr><td>hex short</td><td style="background-color: #0f0; color: #000000;">background-color: #0f0</td></tr>'
|
||||
. '<tr><td>hex long</td><td style="background-color: #1e90ff; color: #ffffff;">background-color: #1e90ff</td></tr>'
|
||||
. '<tr><td>rgb</td><td style="background-color: rgb(255, 99, 71); color: #000000;">background-color: rgb(255, 99, 71)</td></tr>'
|
||||
. '<tr><td>rgba</td><td style="background-color: rgba(30, 144, 255, 0.25); color: #000000;">background-color: rgba(30, 144, 255, 0.25)</td></tr>'
|
||||
. '<tr><td>hsl</td><td style="background-color: hsl(120, 100%, 25%); color: #ffffff;">background-color: hsl(120, 100%, 25%)</td></tr>'
|
||||
. '<tr><td>hsla</td><td style="background-color: hsla(300, 100%, 50%, 0.20); color: #000000;">background-color: hsla(300, 100%, 50%, 0.20)</td></tr>'
|
||||
. '<tr><td>lab</td><td style="background-color: lab(54.29% -19.04 38.25); color: #ffffff;">background-color: lab(54.29% -19.04 38.25)</td></tr>'
|
||||
. '<tr><td>lab alpha</td><td style="background-color: lab(54.29% -19.04 38.25 / 0.35); color: #ffffff;">background-color: lab(54.29% -19.04 38.25 / 0.35)</td></tr>'
|
||||
. '<tr><td>cmyk</td><td style="background-color: cmyk(67, 33, 0, 25); color: #ffffff;">background-color: cmyk(67, 33, 0, 25)</td></tr>'
|
||||
. '</table>';
|
||||
|
||||
foreach ($pdf->color::WEBHEX as $k => $v) {
|
||||
$textcolors .= '<span color="#' . $v . '">' . $k . '</span> ';
|
||||
$bgcolors .= '<span bgcolor="#' . $v . '" color="#333333">' . $k . '</span> ';
|
||||
}
|
||||
|
||||
$html_02 = '<h1>HTML Colors</h1>' . $csscolortypes . '<hr />' . $textcolors . '<hr />' . $bgcolors;
|
||||
|
||||
$pdf->addHTMLCell(html: $html_02, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML D - Transparency Showcase
|
||||
|
||||
$pageV02T = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pdf->setBookmark(
|
||||
name: 'Transparency color showcase',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: '',
|
||||
);
|
||||
|
||||
$baseRectStyle = [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'miterLimit' => 10,
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'none',
|
||||
'fillColor' => 'rgb(0, 64, 128)',
|
||||
];
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getRect(20, 24, 170, 96, 'F', ['all' => $baseRectStyle]));
|
||||
|
||||
$html_transparency = <<<HTML
|
||||
<style>
|
||||
.alpha-demo {
|
||||
font-size: 10pt;
|
||||
color: #ffffff;
|
||||
}
|
||||
.alpha-demo h2 {
|
||||
margin: 0 0 2mm 0;
|
||||
font-size: 16pt;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
}
|
||||
.alpha-demo .line-a {
|
||||
font-size: 12pt;
|
||||
color: rgba(255, 255, 255, 0.48);
|
||||
margin: 0 0 2mm 0;
|
||||
}
|
||||
.alpha-demo .line-b {
|
||||
font-size: 12pt;
|
||||
color: hsla(60, 100%, 86%, 0.58);
|
||||
margin: 0 0 3mm 0;
|
||||
}
|
||||
.alpha-demo .bg-strip {
|
||||
margin-top: 1mm;
|
||||
padding: 1.3mm 1.8mm;
|
||||
background-color: rgba(0, 0, 0, 0.30);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.alpha-demo .swatch {
|
||||
display: inline-block;
|
||||
margin-right: 2mm;
|
||||
padding: 0.7mm 1.6mm;
|
||||
color: rgba(0, 0, 0, 0.86);
|
||||
font-weight: bold;
|
||||
}
|
||||
.alpha-demo .swatch-rgba {
|
||||
background-color: rgba(30, 144, 255, 0.32);
|
||||
}
|
||||
.alpha-demo .swatch-hsla {
|
||||
background-color: hsla(300, 100%, 60%, 0.30);
|
||||
}
|
||||
.alpha-demo .swatch-rgba2 {
|
||||
background-color: rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
</style>
|
||||
<div class="alpha-demo">
|
||||
<h2>Transparency Color Showcase</h2>
|
||||
<p class="line-a">RGBA text: white alpha at 0.48 over a solid blue rectangle</p>
|
||||
<p class="line-b">HSLA text: warm yellow alpha at 0.58 over the same blue base</p>
|
||||
<div class="bg-strip">Background object with alpha: rgba(0, 0, 0, 0.30)</div>
|
||||
<p>
|
||||
<span class="swatch swatch-rgba">RGBA bg 0.32</span>
|
||||
<span class="swatch swatch-hsla">HSLA bg 0.30</span>
|
||||
<span class="swatch swatch-rgba2">RGBA bg 0.45</span>
|
||||
</p>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html_transparency, posx: 24, posy: 28, width: 162);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML C
|
||||
|
||||
$pageV03 = $pdf->addPage();
|
||||
|
||||
$html_03 = '<h1>Various HTML Tests</h1>
|
||||
<font face="courier"><b>thisisaverylongword</b></font> <font face="helvetica"><i>thisisanotherverylongword</i></font> <font face="times"><b>thisisaverylongword</b></font> thisisanotherverylongword <font face="times">thisisaverylongword</font> <font face="courier"><b>thisisaverylongword</b></font> <font face="helvetica"><i>thisisanotherverylongword</i></font> <font face="times"><b>thisisaverylongword</b></font> thisisanotherverylongword <font face="times">thisisaverylongword</font> <font face="courier"><b>thisisaverylongword</b></font> <font face="helvetica"><i>thisisanotherverylongword</i></font> <font face="times"><b>thisisaverylongword</b></font> thisisanotherverylongword <font face="times">thisisaverylongword</font> <font face="courier"><b>thisisaverylongword</b></font> <font face="helvetica"><i>thisisanotherverylongword</i></font> <font face="times"><b>thisisaverylongword</b></font> thisisanotherverylongword <font face="times">thisisaverylongword</font> <font face="courier"><b>thisisaverylongword</b></font> <font face="helvetica"><i>thisisanotherverylongword</i></font> <font face="times"><b>thisisaverylongword</b></font> thisisanotherverylongword <font face="times">thisisaverylongword</font>';
|
||||
|
||||
// Test fonts nesting
|
||||
$htmlt1 = 'Default <font face="courier">Courier <font face="helvetica">Helvetica <font face="times">Times <font face="dejavusans">dejavusans </font>Times </font>Helvetica </font>Courier </font>Default';
|
||||
$htmlt2 = '<small>small text</small> normal <small>small text</small> normal <sub>subscript</sub> normal <sup>superscript</sup> normal';
|
||||
$htmlt3 = '<font size="10" color="#ff7f50">The</font> <font size="10" color="#6495ed">quick</font> <font size="14" color="#dc143c">brown</font> <font size="18" color="#008000">fox</font> <font size="22"><a href="https://tcpdf.org">jumps</a></font> <font size="22" color="#a0522d">over</font> <font size="18" color="#da70d6">the</font> <font size="14" color="#9400d3">lazy</font> <font size="10" color="#4169ef">dog</font>.';
|
||||
|
||||
$html_03 .=
|
||||
'<br />' . $htmlt1 . '<br />' . $htmlt2 . '<br />' . $htmlt3 . '<br />' . $htmlt3 . '<br />' . $htmlt2 . '<br />';
|
||||
|
||||
$html_03 .= '<div><span style="font-size:8pt; line-height:110%;">#<span style="font-size:18pt">1</span>a</span></div>';
|
||||
|
||||
$html_03 .= <<<EOF
|
||||
<hr />
|
||||
<h2>Div Blocks</h2>
|
||||
<div style="background-color:#880000;color:white;">
|
||||
Hello World!<br />
|
||||
Hello
|
||||
</div>
|
||||
<pre style="background-color:#336699;color:white;">
|
||||
int main() {
|
||||
printf("HelloWorld");
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
<tt>Monospace font</tt>, normal font, <tt>monospace font</tt>, normal font.
|
||||
<br />
|
||||
<div style="background-color:#880000;color:white;">DIV LEVEL 1<div style="background-color:#008800;color:white;">DIV LEVEL 2</div>DIV LEVEL 1</div>
|
||||
<br />
|
||||
<span style="background-color:#880000;color:white;">SPAN LEVEL 1 <span style="background-color:#008800;color:white;">SPAN LEVEL 2</span> SPAN LEVEL 1</span>
|
||||
EOF;
|
||||
|
||||
$pdf->addHTMLCell(html: $html_03, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML E-A
|
||||
|
||||
$pageV05A = $pdf->addPage();
|
||||
|
||||
$html_05A = '<h2>HTML Text Alignment (A)</h2>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. <em>Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?</em> <em>Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</em><br /><br /><b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i> -> <b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i> -> <b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i> -> <b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i> -> <b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i> -> <b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i> -> <b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i> -> <b>A</b> + <b>B</b> = <b>C</b> -> <i>C</i> - <i>B</i> = <i>A</i> -> <i>C</i> - <i>A</i> = <i>B</i><br /><br /><b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u> <b>Bold</b><i>Italic</i><u>Underlined</u>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html_05A, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML E-L
|
||||
|
||||
$html_05L = '<p>Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo. Lima Mike November Oscar Papa Quebec Romeo (<em>Sierra-Tango</em>) Uniform Victor Whiskey (<em>Xray-Yankee</em>). Zulu. Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo. Lima Mike November Oscar Papa Quebec Romeo (<em>Sierra-Tango</em>) Uniform Victor Whiskey (<em>Xray-Yankee</em>). Zulu. Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo. Lima Mike November Oscar Papa Quebec Romeo (<em>Sierra-Tango</em>) Uniform Victor Whiskey (<em>Xray-Yankee</em>). Zulu.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html_05L, posx: 20, posy: 100, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML E-B
|
||||
|
||||
$pageV05B = $pdf->addPage();
|
||||
|
||||
$html_05B = '<h2>HTML Text Alignment (B)</h2>
|
||||
<div style="text-align:justify;">JUSTIFY: Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa
|
||||
Quebec Romeo</div>
|
||||
<br />
|
||||
<div style="text-align:left;">LEFT: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br />
|
||||
<div style="text-align:center;">CENTER: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br />
|
||||
<div style="text-align:right;">RIGHT: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br />
|
||||
<div style="text-align:justify;">JUSTIFY: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br />
|
||||
<div style="text-align:justify;">JUSTIFY: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="89" height="30" border="0" /><img src="images/tcpdf_box.svg" alt="TCPDF box" width="100" height="67" border="0" /> <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br />
|
||||
<div style="text-align:left;">LEFT: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="89" height="30" border="0" /><img src="images/tcpdf_box.svg" alt="TCPDF box" width="100" height="67" border="0" /> <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br />
|
||||
<div style="text-align:center;">CENTER: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="89" height="30" border="0" /><img src="images/tcpdf_box.svg" alt="TCPDF box" width="100" height="67" border="0" /> <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br />
|
||||
<div style="text-align:right;">RIGHT: Alfa <i>Bravo</i> Charlie <i>Delta</i> Echo <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="89" height="30" border="0" /><img src="images/tcpdf_box.svg" alt="TCPDF box" width="100" height="67" border="0" /> <i>Foxtrot</i> Golf <i>Hotel</i> India <i>Juliett</i> Kilo <i>Lima</i> Mike <i>November</i> Oscar <i>Papa</i> Quebec <i>Romeo</i> Sierra <i>Tango</i> Uniform <i>Victor</i> Whiskey <i>Xray</i> Yankee <i>Zulu</i></div>
|
||||
<br /><hr />
|
||||
<div><span style="text-align:justify;">a <u>abc</u> abcdefghijkl (abcdef) abcdefg <b>abcdefghi</b> a ((abc)) abcd <img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="89" height="30" border="0" /> abcdef abcdefg <b>abcdefghi</b> a abc abcd abcdef abcdefg <b>abcdefghi</b> a abc abcd abcdef abcdefg <b>abcdefghi</b> a <u>abc</u> abcd abcdef abcdefg <b>abcdefghi</b> a abc \(abcd\) abcdef abcdefg <b>abcdefghi</b> a abc \\\(abcd\\\) abcdef abcdefg <b>abcdefghi</b> a abc abcd abcdef abcdefg <b>abcdefghi</b> a abc abcd abcdef abcdefg <b>abcdefghi</b> a abc abcd abcdef abcdefg abcdefghi a abc abcd <a href="https://tcpdf.org">abcdef abcdefg</a> start a abc before <span style="background-color:yellow">yellow color</span> after a abc abcd abcdef abcdefg abcdefghi a abc abcd end abcdefg abcdefghi a abc abcd abcdef abcdefg abcdefghi a abc abcd abcdef abcdefg abcdefghi a abc abcd abcdef abcdefg abcdefghi a abc abcd abcdef abcdefg abcdefghi a abc abcd abcdef abcdefg abcdefghi a abc abcd abcdef abcdefg abcdefghi a abc abcd abcdef abcdefg abcdefghi<br />abcd abcdef abcdefg abcdefghi<br />abcd abcde abcdef</span></div><hr />';
|
||||
|
||||
$pdf->addHTMLCell(html: $html_05B, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML F
|
||||
|
||||
$pageV06 = $pdf->addPage();
|
||||
|
||||
$html_06 = <<<EOF
|
||||
<!-- EXAMPLE OF CSS STYLE -->
|
||||
<style>
|
||||
h1 {
|
||||
color: navy;
|
||||
font-family: times;
|
||||
font-size: 24pt;
|
||||
text-decoration: underline;
|
||||
}
|
||||
p.first {
|
||||
color: #003300;
|
||||
font-family: helvetica;
|
||||
font-size: 12pt;
|
||||
}
|
||||
p.first span {
|
||||
color: #006600;
|
||||
font-style: italic;
|
||||
}
|
||||
p#second {
|
||||
color: rgb(00,63,127);
|
||||
font-family: times;
|
||||
font-size: 12pt;
|
||||
text-align: justify;
|
||||
}
|
||||
p#second > span {
|
||||
background-color: #FFFFAA;
|
||||
}
|
||||
table.first {
|
||||
color: #003300;
|
||||
font-family: helvetica;
|
||||
font-size: 8pt;
|
||||
border-left: 3px solid red;
|
||||
border-right: 3px solid #FF00FF;
|
||||
border-top: 3px solid green;
|
||||
border-bottom: 3px solid blue;
|
||||
background-color: #ccffcc;
|
||||
}
|
||||
td {
|
||||
border: 2px solid blue;
|
||||
background-color: #ffffee;
|
||||
}
|
||||
td.second {
|
||||
border: 2px dashed green;
|
||||
}
|
||||
div.test {
|
||||
color: #CC0000;
|
||||
background-color: #FFFF66;
|
||||
font-family: helvetica;
|
||||
font-size: 10pt;
|
||||
border-style: solid solid solid solid;
|
||||
border-width: 2px 2px 2px 2px;
|
||||
border-color: green #FF00FF blue red;
|
||||
text-align: center;
|
||||
}
|
||||
.lowercase {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1 class="title">Example of <i style="color:#990000">XHTML + CSS</i></h1>
|
||||
|
||||
<p class="first">Example of paragraph with class selector. <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sed imperdiet lectus. Phasellus quis velit velit, non condimentum quam. Sed neque urna, ultrices ac volutpat vel, laoreet vitae augue. Sed vel velit erat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras eget velit nulla, eu sagittis elit. Nunc ac arcu est, in lobortis tellus. Praesent condimentum rhoncus sodales. In hac habitasse platea dictumst. Proin porta eros pharetra enim tincidunt dignissim nec vel dolor. Cras sapien elit, ornare ac dignissim eu, ultricies ac eros. Maecenas augue magna, ultrices a congue in, mollis eu nulla. Nunc venenatis massa at est eleifend faucibus. Vivamus sed risus lectus, nec interdum nunc.</span></p>
|
||||
|
||||
<p id="second">Example of paragraph with ID selector. <span>Fusce et felis vitae diam lobortis sollicitudin. Aenean tincidunt accumsan nisi, id vehicula quam laoreet elementum. Phasellus egestas interdum erat, et viverra ipsum ultricies ac. Praesent sagittis augue at augue volutpat eleifend. Cras nec orci neque. Mauris bibendum posuere blandit. Donec feugiat mollis dui sit amet pellentesque. Sed a enim justo. Donec tincidunt, nisl eget elementum aliquam, odio ipsum ultrices quam, eu porttitor ligula urna at lorem. Donec varius, eros et convallis laoreet, ligula tellus consequat felis, ut ornare metus tellus sodales velit. Duis sed diam ante. Ut rutrum malesuada massa, vitae consectetur ipsum rhoncus sed. Suspendisse potenti. Pellentesque a congue massa.</span></p>
|
||||
|
||||
<div class="test">example of DIV with border and fill.
|
||||
<br />Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
<br /><span class="lowercase">text-transform <b>LOWERCASE</b> Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
|
||||
<br /><span class="uppercase">text-transform <b>uppercase</b> Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
|
||||
<br /><span class="capitalize">text-transform <b>cAPITALIZE</b> Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
|
||||
</div>
|
||||
EOF;
|
||||
|
||||
$pdf->addHTMLCell(html: $html_06, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML A
|
||||
|
||||
$pageV01 = $pdf->addPage();
|
||||
|
||||
$bfont6 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
$pdf->page->addContent($bfont6['out']);
|
||||
|
||||
$style_cell = [
|
||||
'all' => [
|
||||
'lineWidth' => 1,
|
||||
'lineCap' => 'round',
|
||||
'lineJoin' => 'round',
|
||||
'miterLimit' => 1,
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'green',
|
||||
'fillColor' => '#fdfca5',
|
||||
],
|
||||
];
|
||||
|
||||
$html_01 = '<h1>HTML Example A</h1>
|
||||
Some special characters: < € € € & è è © > \\slash \\\\double-slash \\\\\\triple-slash
|
||||
<h2>List</h2>
|
||||
List example:
|
||||
<ol>
|
||||
<li><b>bold text</b></li>
|
||||
<li><i>italic text</i></li>
|
||||
<li><u>underlined text</u></li>
|
||||
<li><b>b<i>bi<u>biu</u>bi</i>b</b></li>
|
||||
<li><a href="https://tcpdf.org" dir="ltr">link to https://tcpdf.org</a></li>
|
||||
<li>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.<br />Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</li>
|
||||
<li>SUBLIST
|
||||
<ol>
|
||||
<li>row one
|
||||
<ul>
|
||||
<li>sublist</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>row two</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><b>T</b>E<i>S</i><u>T</u> <del>line through</del></li>
|
||||
<li><font size="+3">font + 3</font></li>
|
||||
<li><small>small text</small> normal <small>small text</small> normal <sub>subscript</sub> normal <sup>superscript</sup> normal</li>
|
||||
</ol>
|
||||
<dl>
|
||||
<dt>Coffee</dt>
|
||||
<dd>Black hot drink</dd>
|
||||
<dt>Milk</dt>
|
||||
<dd>White cold drink</dd>
|
||||
</dl>
|
||||
|
||||
<div style="text-align:center">The words “<span dir="rtl">מזל [mazel] טוב [tov]</span>” mean “Congratulations!”</div>
|
||||
|
||||
<p>This is just an example of html code to demonstrate some supported CSS inline styles.
|
||||
<span style="font-weight: bold;">bold text</span>
|
||||
<span style="text-decoration: line-through;">line-trough</span>
|
||||
<span style="text-decoration: underline line-through;">underline and line-trough</span>
|
||||
<span style="color: rgb(0, 128, 64);">color</span>
|
||||
<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">background color</span>
|
||||
<span style="font-weight: bold;">bold</span>
|
||||
<span style="font-size: xx-small;">xx-small</span>
|
||||
<span style="font-size: x-small;">x-small</span>
|
||||
<span style="font-size: small;">small</span>
|
||||
<span style="font-size: medium;">medium</span>
|
||||
<span style="font-size: large;">large</span>
|
||||
<span style="font-size: x-large;">x-large</span>
|
||||
<span style="font-size: xx-large;">xx-large</span>
|
||||
</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html_01, posx: 20, posy: 10, width: 150, height: 0, cell: null, styles: $style_cell);
|
||||
|
||||
// ----------
|
||||
|
||||
$pageVC = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($bfont6['out']);
|
||||
|
||||
$html_vc1 = <<<HTML
|
||||
<style>
|
||||
.vc-box {
|
||||
width: 150mm;
|
||||
height: 90mm;
|
||||
border: 0.6mm solid #003366;
|
||||
background-color: #e9f2ff;
|
||||
}
|
||||
.vc-fill {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.vc-content {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
color: #002244;
|
||||
}
|
||||
</style>
|
||||
<div class="vc-box">
|
||||
<table class="vc-fill" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="vc-content">
|
||||
<h1>Vertically Centered Block</h1>
|
||||
<p>This content is centered in the middle of the box.</p>
|
||||
<p><b>HTML:</b> headings, paragraphs, and inline formatting.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html_vc1, posx: 20, posy: 20);
|
||||
|
||||
// ----------
|
||||
|
||||
$html_vc2 = <<<HTML
|
||||
<table border="1" cellpadding="0" cellspacing="0" style="width:150mm; height:100mm; background-color:blue; border-color:#003366;">
|
||||
<tr>
|
||||
<td style="height:100mm; vertical-align:middle; text-align:center; color:cmyk(100,0,0,0);">
|
||||
<h1>Vertically Centered Block</h1>
|
||||
<p>This content is centered in the middle of the box.</p>
|
||||
<p><b>HTML:</b> headings, paragraphs, and inline formatting.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html_vc2, posx: 20, posy: 120, width: 150, height: 100);
|
||||
|
||||
// ----------
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E032_html_lists.php
|
||||
*
|
||||
* @since 2026-04-28
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 032');
|
||||
$pdf->setTitle('HTML List Item CSS Variations');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example html list css ul ol li');
|
||||
$pdf->setPDFFilename('032_html_lists.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
// $bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->setBookmark(
|
||||
name: 'HTML list item CSS variations',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: '',
|
||||
);
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// This example showcases all currently supported list-item CSS behavior:
|
||||
// - list-style-type
|
||||
// - list-style-position (inside / outside)
|
||||
// - margin-left / padding-left
|
||||
// - text-indent first-line behavior on list-item text
|
||||
// - nested OL/UL interactions
|
||||
// - li::marker styling (color, font-weight, font-style)
|
||||
// - list-style-image CSS property parsing
|
||||
|
||||
$html = <<<HTML
|
||||
<style>
|
||||
body {
|
||||
color: #222222;
|
||||
font-size: 10pt;
|
||||
}
|
||||
h1 {
|
||||
color: #0f2b46;
|
||||
margin-bottom: 3mm;
|
||||
}
|
||||
h2 {
|
||||
color: #1e4f80;
|
||||
margin-top: 4mm;
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
.note {
|
||||
font-size: 8pt;
|
||||
color: #5b5b5b;
|
||||
}
|
||||
.panel {
|
||||
background-color: #f7fbff;
|
||||
padding: 2mm;
|
||||
margin-bottom: 2.5mm;
|
||||
}
|
||||
|
||||
/* Variation set: list-style-type */
|
||||
.ul-disc { list-style-type: disc; }
|
||||
.ul-circle { list-style-type: circle; }
|
||||
.ul-square { list-style-type: square; }
|
||||
.ol-decimal { list-style-type: decimal; }
|
||||
.ol-upper-alpha { list-style-type: upper-alpha; }
|
||||
.ol-lower-roman { list-style-type: lower-roman; }
|
||||
|
||||
/* Variation set: list-style-position */
|
||||
.pos-inside { list-style-position: inside; }
|
||||
.pos-outside { list-style-position: outside; }
|
||||
|
||||
/* Variation set: margin/padding on containers and items */
|
||||
.list-shift-a {
|
||||
margin-left: 0mm;
|
||||
padding-left: 3mm;
|
||||
}
|
||||
.list-shift-b {
|
||||
margin-left: 6mm;
|
||||
padding-left: 1mm;
|
||||
}
|
||||
.list-shift-c {
|
||||
margin-left: 10mm;
|
||||
padding-left: 0mm;
|
||||
}
|
||||
.list-shift-a li { margin-left: 0mm; padding-left: 0mm; }
|
||||
.list-shift-b li { margin-left: 1mm; padding-left: 1mm; }
|
||||
.list-shift-c li { margin-left: 2mm; padding-left: 0mm; }
|
||||
|
||||
/* Variation set: text-indent (first-line and hanging) */
|
||||
.indent-first li { text-indent: 4mm; }
|
||||
.indent-hanging li { text-indent: -2mm; }
|
||||
|
||||
/* Variation set: li::marker styling */
|
||||
.marker-red li::marker { color: red; }
|
||||
.marker-blue li::marker { color: blue; }
|
||||
.marker-green li::marker { color: #008000; }
|
||||
|
||||
/* Variation set: list-style-image (custom bullets) */
|
||||
.list-img-svg { list-style-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiPjxjaXJjbGUgY3g9IjQiIGN5PSI0IiByPSI0IiBmaWxsPSIjRkY2NjAwIi8+PC9zdmc+); }
|
||||
|
||||
/* Visual hint only */
|
||||
.marker-guide,
|
||||
.marker-line {
|
||||
border-left: 0.2mm solid #ff0000;
|
||||
padding-left: 1.5mm;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>HTML List Item CSS Variations (Current Support)</h1>
|
||||
|
||||
<div class="panel">
|
||||
<h2>1) Unordered list styles (`list-style-type`)</h2>
|
||||
<ul class="ul-disc marker-guide">
|
||||
<li>Disc marker</li>
|
||||
<li>Nested sample
|
||||
<ul class="ul-circle">
|
||||
<li>Circle marker</li>
|
||||
<li>Another nested item</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="ul-square marker-guide">
|
||||
<li>Square marker</li>
|
||||
<li>Second square marker item</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>2) Ordered list styles (`list-style-type`)</h2>
|
||||
<ol class="ol-decimal marker-guide">
|
||||
<li>Decimal marker</li>
|
||||
<li>Second item</li>
|
||||
</ol>
|
||||
<ol class="ol-upper-alpha marker-guide">
|
||||
<li>Upper-alpha marker</li>
|
||||
<li>Second item</li>
|
||||
</ol>
|
||||
<ol class="ol-lower-roman marker-guide">
|
||||
<li>Lower-roman marker</li>
|
||||
<li>Second item</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>3) Marker position (`list-style-position`)</h2>
|
||||
<ul class="ul-disc pos-outside marker-guide">
|
||||
<li>Outside marker with long text to show wrap behavior for this rendering path in the PDF engine.</li>
|
||||
<li>Second outside item</li>
|
||||
</ul>
|
||||
<ul class="ul-disc pos-inside marker-guide">
|
||||
<li>Inside marker with long text to show wrap behavior for this rendering path in the PDF engine.</li>
|
||||
<li>Second inside item</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>4) Container and item indentation (`margin-left` / `padding-left`)</h2>
|
||||
<ul class="ul-disc list-shift-a marker-guide">
|
||||
<li>Shift A</li>
|
||||
<li>Shift A nested
|
||||
<ol class="ol-decimal">
|
||||
<li>Nested ordered item</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="ul-disc list-shift-b marker-guide">
|
||||
<li>Shift B</li>
|
||||
<li>Shift B nested
|
||||
<ol class="ol-upper-alpha">
|
||||
<li>Nested ordered item</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="ul-disc list-shift-c marker-guide">
|
||||
<li>Shift C</li>
|
||||
<li>Shift C nested
|
||||
<ol class="ol-lower-roman">
|
||||
<li>Nested ordered item</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>5) Mixed nesting matrix (`ol` inside `ul`, `ul` inside `ol`)</h2>
|
||||
<ul class="ul-square marker-guide">
|
||||
<li>UL root item
|
||||
<ol class="ol-decimal pos-outside">
|
||||
<li>OL nested in UL
|
||||
<ul class="ul-circle pos-inside">
|
||||
<li>UL nested in OL</li>
|
||||
<li>Second nested UL item</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>6) List text indentation (`text-indent`)</h2>
|
||||
<ol class="ol-decimal indent-first marker-guide">
|
||||
<li>First-line indent with long text to make wrapping visible in the list-item rendering path. First-line indent with long text to make wrapping visible in the list-item rendering path.</li>
|
||||
<li><span>First-line</span> indent with long text to <span>make</span> wrapping visible in the list-item rendering path. (B) First-line indent with long text to make wrapping visible in the list-item rendering path.</li>
|
||||
<li>Second item with first-line indent style applied.</li>
|
||||
</ol>
|
||||
|
||||
<ol class="ol-decimal indent-hanging marker-guide">
|
||||
<li>Hanging-indent style (negative text-indent) with long text to highlight first-line offset behavior.</li>
|
||||
<li>Second item using the same hanging-indent rule.</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>7) Marker color styling (`li::marker`)</h2>
|
||||
<ol class="ol-decimal marker-red marker-guide">
|
||||
<li>Red marker color applied via li::marker selector</li>
|
||||
<li>Second item with red marker styling</li>
|
||||
</ol>
|
||||
<ul class="ul-disc marker-blue marker-guide">
|
||||
<li>Blue marker color applied via li::marker selector</li>
|
||||
<li>Second unordered item with blue marker</li>
|
||||
</ul>
|
||||
<ol class="ol-upper-alpha marker-green marker-guide">
|
||||
<li>Green marker color applied via li::marker selector</li>
|
||||
<li>Second item with green marker styling</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>8) Custom bullet images (`list-style-image`)</h2>
|
||||
<p class="note">Note: Image bullet rendering is subject to image loading availability and fallback behavior.</p>
|
||||
<ul class="list-img-svg marker-guide">
|
||||
<li>Custom SVG bullet marker image</li>
|
||||
<li>Second item with custom image bullet</li>
|
||||
<li>Nested list with custom bullets
|
||||
<ul class="list-img-svg">
|
||||
<li>Nested custom image bullet item</li>
|
||||
<li>Another nested custom image bullet</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 10, posy: 20, width: 190);
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E033_geometric_transformations.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 033');
|
||||
$pdf->setTitle('Geometric Transformations');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf transformations rotate scale translate skew matrix');
|
||||
$pdf->setPDFFilename('033_geometric_transformations.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 8);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Transformations', link: '', level: 1);
|
||||
|
||||
// Document title and explanation
|
||||
$titleHtml = <<<HTML
|
||||
<h1 style="font-size:16pt; color:#003366;">Geometric Transformations</h1>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
This example demonstrates the geometric transformation operations available in tc-lib-pdf:
|
||||
<b>scaling</b>, <b>translation</b>, <b>rotation</b>, <b>skewing</b>, <b>mirroring</b>,
|
||||
and combined <b>affine transformations.</b>
|
||||
Each operation is shown with a reference rectangle (black) and the transformed result (red).
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $titleHtml, posx: 15, posy: 15, width: 180);
|
||||
|
||||
// Geometric Transformations
|
||||
|
||||
$rect_style = [
|
||||
'lineWidth' => 0.3,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'black',
|
||||
'fillColor' => 'black',
|
||||
];
|
||||
|
||||
$transform_style = [
|
||||
'lineWidth' => 0.3,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'red',
|
||||
'fillColor' => 'red',
|
||||
];
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Scaling: 150% around (50, 80)',
|
||||
50,
|
||||
60,
|
||||
65,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Scaling
|
||||
$t1 = $pdf->graph->getBasicRect(50, 70, 40, 10, 'D', $rect_style);
|
||||
$t1 .= $pdf->graph->getStartTransform();
|
||||
// Scale by 150% centered by (50,80) which is the lower left corner of the rectangle
|
||||
$t1 .= $pdf->graph->getScaling(1.5, 1.5, 50, 80);
|
||||
$t1 .= $pdf->graph->getBasicRect(50, 70, 40, 10, 'D', $transform_style);
|
||||
$t1 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t1);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Translation: +7 x, +5 y',
|
||||
125,
|
||||
66,
|
||||
65,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Translation
|
||||
$t2 = $pdf->graph->getBasicRect(125, 70, 40, 10, 'D');
|
||||
$t2 .= $pdf->graph->getStartTransform();
|
||||
// Translate 7 to the right, 5 to the bottom
|
||||
$t2 .= $pdf->graph->getTranslation(7, 5);
|
||||
$t2 .= $pdf->graph->getBasicRect(125, 70, 40, 10, 'D', $transform_style);
|
||||
$t2 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t2);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Rotation: 20 degrees around (70, 110)',
|
||||
50,
|
||||
112,
|
||||
70,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Rotation
|
||||
$t3 = $pdf->graph->getBasicRect(70, 100, 40, 10, 'D');
|
||||
$t3 .= $pdf->graph->getStartTransform();
|
||||
// Rotate 20 degrees counter-clockwise centered by (70,110) which is the lower left corner of the rectangle
|
||||
$t3 .= $pdf->graph->getRotation(20, 70, 110);
|
||||
$t3 .= $pdf->graph->getBasicRect(70, 100, 40, 10, 'D', $transform_style);
|
||||
$t3 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t3);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Skewing: 30 degrees on x-axis',
|
||||
125,
|
||||
96,
|
||||
65,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Skewing
|
||||
$t4 = $pdf->graph->getBasicRect(125, 100, 40, 10, 'D');
|
||||
$t4 .= $pdf->graph->getStartTransform();
|
||||
// skew 30 degrees along the x-axis centered by (125,110) which is the lower left corner of the rectangle
|
||||
$t4 .= $pdf->graph->getSkewing(30, 0, 125, 110);
|
||||
$t4 .= $pdf->graph->getBasicRect(125, 100, 40, 10, 'D', $transform_style);
|
||||
$t4 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t4);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Horizontal mirror at x = 70',
|
||||
50,
|
||||
126,
|
||||
65,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Mirroring Horizontally
|
||||
$t5 = $pdf->graph->getBasicRect(70, 130, 40, 10, 'D');
|
||||
$t5 .= $pdf->graph->getStartTransform();
|
||||
// mirror horizontally with axis of reflection at x-position 70 (left side of the rectangle)
|
||||
$t5 .= $pdf->graph->getHorizMirroring(70);
|
||||
$t5 .= $pdf->graph->getBasicRect(70, 130, 40, 10, 'D', $transform_style);
|
||||
$t5 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t5);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Vertical mirror at y = 140',
|
||||
125,
|
||||
126,
|
||||
65,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Mirroring Vertically
|
||||
$t6 = $pdf->graph->getBasicRect(125, 130, 40, 10, 'D');
|
||||
$t6 .= $pdf->graph->getStartTransform();
|
||||
// mirror vertically with axis of reflection at y-position 140 (bottom side of the rectangle)
|
||||
$t6 .= $pdf->graph->getVertMirroring(140);
|
||||
$t6 .= $pdf->graph->getBasicRect(125, 130, 40, 10, 'D', $transform_style);
|
||||
$t6 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t6);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Point reflection at (70, 170)',
|
||||
50,
|
||||
156,
|
||||
65,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Point Reflection
|
||||
$t7 = $pdf->graph->getBasicRect(70, 160, 40, 10, 'D');
|
||||
$t7 .= $pdf->graph->getStartTransform();
|
||||
// point reflection at the lower left point of rectangle
|
||||
$t7 .= $pdf->graph->getPointMirroring(70, 170);
|
||||
$t7 .= $pdf->graph->getBasicRect(70, 160, 40, 10, 'D', $transform_style);
|
||||
$t7 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t7);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Line reflection through (120, 170), angle -20 degrees',
|
||||
125,
|
||||
156,
|
||||
70,
|
||||
6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
));
|
||||
|
||||
// Mirroring against a straigth line described by a point (120, 120) and an angle -20°
|
||||
$angle = -20;
|
||||
$px = 120;
|
||||
$py = 170;
|
||||
|
||||
// just for visualisation: the straight line to mirror against
|
||||
$t8 = $pdf->graph->getLine($px - 1, $py - 1, $px + 1, $py + 1, [
|
||||
'lineColor' => 'green',
|
||||
]);
|
||||
$t8 .= $pdf->graph->getLine($px - 1, $py + 1, $px + 1, $py - 1, [
|
||||
'lineColor' => 'green',
|
||||
]);
|
||||
$t8 .= $pdf->graph->getStartTransform();
|
||||
$t8 .= $pdf->graph->getRotation($angle, $px, $py);
|
||||
$t8 .= $pdf->graph->getLine($px - 5, $py, $px + 60, $py, [
|
||||
'lineColor' => 'green',
|
||||
]);
|
||||
$t8 .= $pdf->graph->getStopTransform();
|
||||
$t8 .= $pdf->graph->getBasicRect(125, 160, 40, 10, 'D', $rect_style);
|
||||
$t8 .= $pdf->graph->getStartTransform();
|
||||
// mirror against the straight line
|
||||
$t8 .= $pdf->graph->getReflection($angle, $px, $py);
|
||||
$t8 .= $pdf->graph->getBasicRect(125, 160, 40, 10, 'D', $transform_style);
|
||||
$t8 .= $pdf->graph->getStopTransform();
|
||||
$pdf->page->addContent($t8);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E034_color_gradient_mesh.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 034');
|
||||
$pdf->setTitle('Color Gradient Mesh');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf color gradient mesh shading patch');
|
||||
$pdf->setPDFFilename('034_color_gradient_mesh.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Color Gradients', link: '', level: 1);
|
||||
|
||||
$html =
|
||||
'<h1>Color Gradients and Meshes</h1>'
|
||||
. '<p>This page demonstrates linear and radial gradients together with Coons patch meshes rendered by tc-lib-pdf.</p>';
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
// Linear gradient
|
||||
$lingrad = $pdf->graph->getLinearGradient(20, 80, 80, 80, 'red', 'blue', [0, 0, 1, 0]);
|
||||
$pdf->page->addContent($lingrad);
|
||||
|
||||
// Radial Gradient
|
||||
$radgrad = $pdf->graph->getRadialGradient(110, 80, 80, 80, 'white', 'black', [0.5, 0.5, 1, 1, 1.2]);
|
||||
$pdf->page->addContent($radgrad);
|
||||
|
||||
// CoonsPatchMesh
|
||||
$coonspatchmesh1 = $pdf->graph->getCoonsPatchMeshWithCoords(20, 180, 80, 80, 'yellow', 'blue', 'green', 'red');
|
||||
$pdf->page->addContent($coonspatchmesh1);
|
||||
|
||||
// set the coordinates for the cubic Bézier points x1,y1 ... x12, y12 of the patch
|
||||
$coords = [
|
||||
0.00,
|
||||
0.00,
|
||||
0.33,
|
||||
0.20,
|
||||
//lower left
|
||||
0.67,
|
||||
0.00,
|
||||
1.00,
|
||||
0.00,
|
||||
0.80,
|
||||
0.33,
|
||||
//lower right
|
||||
0.80,
|
||||
0.67,
|
||||
1.00,
|
||||
1.00,
|
||||
0.67,
|
||||
0.80,
|
||||
//upper right
|
||||
0.33,
|
||||
1.00,
|
||||
0.00,
|
||||
1.00,
|
||||
0.20,
|
||||
0.67,
|
||||
//upper left
|
||||
0.00,
|
||||
0.33,
|
||||
]; //lower left
|
||||
|
||||
// paint a coons patch gradient with the above coordinates
|
||||
$coonspatchmesh2 = $pdf->graph->getCoonsPatchMeshWithCoords(
|
||||
110,
|
||||
180,
|
||||
80,
|
||||
80,
|
||||
'yellow',
|
||||
'blue',
|
||||
'green',
|
||||
'red',
|
||||
$coords,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
$pdf->page->addContent($coonspatchmesh2);
|
||||
|
||||
// ----------
|
||||
|
||||
$page02 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Color gradient mesh', link: '', level: 1);
|
||||
|
||||
// first patch: f = 0
|
||||
$patch_array[0]['f'] = 0;
|
||||
$patch_array[0]['points'] = [
|
||||
0.00,
|
||||
0.00,
|
||||
0.33,
|
||||
0.00,
|
||||
0.67,
|
||||
0.00,
|
||||
1.00,
|
||||
0.00,
|
||||
1.00,
|
||||
0.33,
|
||||
0.8,
|
||||
0.67,
|
||||
1.00,
|
||||
1.00,
|
||||
0.67,
|
||||
0.8,
|
||||
0.33,
|
||||
1.80,
|
||||
0.00,
|
||||
1.00,
|
||||
0.00,
|
||||
0.67,
|
||||
0.00,
|
||||
0.33,
|
||||
];
|
||||
$patch_array[0]['colors'][0] = [
|
||||
'red' => 1,
|
||||
'green' => 1,
|
||||
'blue' => 0,
|
||||
'alpha' => 1,
|
||||
];
|
||||
$patch_array[0]['colors'][1] = [
|
||||
'red' => 1,
|
||||
'green' => 1,
|
||||
'blue' => 1,
|
||||
'alpha' => 1,
|
||||
];
|
||||
$patch_array[0]['colors'][2] = [
|
||||
'red' => 0,
|
||||
'green' => 1,
|
||||
'blue' => 0,
|
||||
'alpha' => 1,
|
||||
];
|
||||
$patch_array[0]['colors'][3] = [
|
||||
'red' => 1,
|
||||
'green' => 0,
|
||||
'blue' => 0,
|
||||
'alpha' => 1,
|
||||
];
|
||||
|
||||
// second patch - above the other: f = 2
|
||||
$patch_array[1]['f'] = 2;
|
||||
$patch_array[1]['points'] = [
|
||||
0.00,
|
||||
1.33,
|
||||
0.00,
|
||||
1.67,
|
||||
0.00,
|
||||
2.00,
|
||||
0.33,
|
||||
2.00,
|
||||
0.67,
|
||||
2.00,
|
||||
1.00,
|
||||
2.00,
|
||||
1.00,
|
||||
1.67,
|
||||
1.5,
|
||||
1.33,
|
||||
];
|
||||
$patch_array[1]['colors'][0] = [
|
||||
'red' => 0,
|
||||
'green' => 0,
|
||||
'blue' => 0,
|
||||
'alpha' => 1,
|
||||
];
|
||||
$patch_array[1]['colors'][1] = [
|
||||
'red' => 1,
|
||||
'green' => 0,
|
||||
'blue' => 1,
|
||||
'alpha' => 1,
|
||||
];
|
||||
|
||||
// third patch - right of the above: f = 3
|
||||
$patch_array[2]['f'] = 3;
|
||||
$patch_array[2]['points'] = [
|
||||
1.33,
|
||||
0.80,
|
||||
1.67,
|
||||
1.50,
|
||||
2.00,
|
||||
1.00,
|
||||
2.00,
|
||||
1.33,
|
||||
2.00,
|
||||
1.67,
|
||||
2.00,
|
||||
2.00,
|
||||
1.67,
|
||||
2.00,
|
||||
1.33,
|
||||
2.00,
|
||||
];
|
||||
$patch_array[2]['colors'][0] = [
|
||||
'red' => 0,
|
||||
'green' => 1,
|
||||
'blue' => 1,
|
||||
'alpha' => 1,
|
||||
];
|
||||
$patch_array[2]['colors'][1] = [
|
||||
'red' => 0,
|
||||
'green' => 0,
|
||||
'blue' => 0,
|
||||
'alpha' => 1,
|
||||
];
|
||||
|
||||
// fourth patch - below the above, which means left(?) of the above: f = 1
|
||||
$patch_array[3]['f'] = 1;
|
||||
$patch_array[3]['points'] = [
|
||||
2.00,
|
||||
0.67,
|
||||
2.00,
|
||||
0.33,
|
||||
2.00,
|
||||
0.00,
|
||||
1.67,
|
||||
0.00,
|
||||
1.33,
|
||||
0.00,
|
||||
1.00,
|
||||
0.00,
|
||||
1.00,
|
||||
0.33,
|
||||
0.8,
|
||||
0.67,
|
||||
];
|
||||
$patch_array[3]['colors'][0] = [
|
||||
'red' => 0,
|
||||
'green' => 0,
|
||||
'blue' => 0,
|
||||
'alpha' => 1,
|
||||
];
|
||||
$patch_array[3]['colors'][1] = [
|
||||
'red' => 0,
|
||||
'green' => 0,
|
||||
'blue' => 1,
|
||||
'alpha' => 1,
|
||||
];
|
||||
|
||||
$coonspatchmesh3 = $pdf->graph->getCoonsPatchMesh(0, 0, 210, 297, $patch_array, 0, 2);
|
||||
$pdf->page->addContent($coonspatchmesh3);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E035_registration_marks.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 035');
|
||||
$pdf->setTitle('Registration Marks');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf registration marks prepress crop bleed print');
|
||||
$pdf->setPDFFilename('035_registration_marks.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Crop Marks and Color Maps', link: '', level: 1);
|
||||
|
||||
$html = <<<HTML
|
||||
<h1>Registration Marks</h1>
|
||||
<p>
|
||||
This example shows crop marks, registration targets, and color registration bars,
|
||||
including spot-color bars used for print alignment checks.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 15, width: 180);
|
||||
|
||||
$style1 = [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'darkorange',
|
||||
'fillColor' => 'palegreen',
|
||||
];
|
||||
|
||||
$pdf->graph->add($style1);
|
||||
|
||||
$style2 = $pdf->graph->getCurrentStyleArray();
|
||||
|
||||
$posx = 60;
|
||||
$posy = 120;
|
||||
|
||||
// Crop Marks
|
||||
|
||||
$crpmrk1 = $pdf->graph->getCropMark($posx, $posy, 10, 10, 'TL', $style2);
|
||||
$pdf->page->addContent($crpmrk1);
|
||||
|
||||
$crpmrk2 = $pdf->graph->getCropMark($posx + 90, $posy, 10, 10, 'TR', $style2);
|
||||
$pdf->page->addContent($crpmrk2);
|
||||
|
||||
$crpmrk3 = $pdf->graph->getCropMark($posx, $posy + 50, 10, 10, 'BL', $style2);
|
||||
$pdf->page->addContent($crpmrk3);
|
||||
|
||||
$crpmrk4 = $pdf->graph->getCropMark($posx + 90, $posy + 50, 10, 10, 'BR', $style2);
|
||||
$pdf->page->addContent($crpmrk4);
|
||||
|
||||
$crpmrk5 = $pdf->graph->getCropMark($posx + 45, $posy - 5, 5, 5, 'LTR');
|
||||
$pdf->page->addContent($crpmrk5);
|
||||
|
||||
$crpmrk6 = $pdf->graph->getCropMark($posx + 45, $posy + 55, 5, 5, 'LBR');
|
||||
$pdf->page->addContent($crpmrk6);
|
||||
|
||||
$crpmrk7 = $pdf->graph->getCropMark($posx - 5, $posy + 25, 5, 5, 'TLB');
|
||||
$pdf->page->addContent($crpmrk7);
|
||||
|
||||
$crpmrk8 = $pdf->graph->getCropMark($posx + 95, $posy + 25, 5, 5, 'TRB');
|
||||
$pdf->page->addContent($crpmrk8);
|
||||
|
||||
$crpmrk9 = $pdf->graph->getCropMark($posx + 45, $posy + 70, 5, 5, 'TLBR', [
|
||||
'lineColor' => 'lime',
|
||||
]);
|
||||
$pdf->page->addContent($crpmrk9);
|
||||
|
||||
// Registration Marks
|
||||
|
||||
$regmrk1 = $pdf->graph->getRegistrationMark($posx - 10, $posy - 10, 5, false);
|
||||
$pdf->page->addContent($regmrk1);
|
||||
|
||||
$regmrk2 = $pdf->graph->getRegistrationMark($posx + 100, $posy - 10, 5, true);
|
||||
$pdf->page->addContent($regmrk2);
|
||||
|
||||
$regmrk3 = $pdf->graph->getRegistrationMark($posx - 10, $posy + 60, 5, true);
|
||||
$pdf->page->addContent($regmrk3);
|
||||
|
||||
$regmrk4 = $pdf->graph->getRegistrationMark($posx + 100, $posy + 60, 5, false, 'blue');
|
||||
$pdf->page->addContent($regmrk4);
|
||||
|
||||
// CYMK Registration Mark
|
||||
$regmrk5 = $pdf->graph->getCmykRegistrationMark($posx + 100, $posy + 85, 8);
|
||||
$pdf->page->addContent($regmrk5);
|
||||
|
||||
// Add Spot Colors
|
||||
|
||||
$color_custom_dark_green = new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 1,
|
||||
'magenta' => 0.5,
|
||||
'yellow' => 0.8,
|
||||
'key' => 0.45,
|
||||
'alpha' => 0,
|
||||
]);
|
||||
$pdf->color->addSpotColor('Custom Dark Green', $color_custom_dark_green);
|
||||
|
||||
$color_custom_light_yellow = new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0,
|
||||
'magenta' => 0,
|
||||
'yellow' => 0.55,
|
||||
'key' => 0,
|
||||
'alpha' => 0,
|
||||
]);
|
||||
$pdf->color->addSpotColor('Custom Light Yellow', $color_custom_light_yellow);
|
||||
|
||||
$color_custom_black = new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0,
|
||||
'magenta' => 0,
|
||||
'yellow' => 0,
|
||||
'key' => 1,
|
||||
'alpha' => 0,
|
||||
]);
|
||||
$pdf->color->addSpotColor('Custom Black', $color_custom_black);
|
||||
|
||||
$color_custom_red = new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.3,
|
||||
'magenta' => 1,
|
||||
'yellow' => 0.9,
|
||||
'key' => 0.1,
|
||||
'alpha' => 0,
|
||||
]);
|
||||
$pdf->color->addSpotColor('Custom Red', $color_custom_red);
|
||||
|
||||
$color_custom_green = new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 1,
|
||||
'magenta' => 0.3,
|
||||
'yellow' => 1,
|
||||
'key' => 0,
|
||||
'alpha' => 0,
|
||||
]);
|
||||
$pdf->color->addSpotColor('Custom Green', $color_custom_green);
|
||||
|
||||
$color_custom_blue = new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 1,
|
||||
'magenta' => 0.6,
|
||||
'yellow' => 0.1,
|
||||
'key' => 0.05,
|
||||
'alpha' => 0,
|
||||
]);
|
||||
$pdf->color->addSpotColor('Custom Blue', $color_custom_blue);
|
||||
|
||||
$color_custom_yellow = new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0,
|
||||
'magenta' => 0.2,
|
||||
'yellow' => 1,
|
||||
'key' => 0,
|
||||
'alpha' => 0,
|
||||
]);
|
||||
$pdf->color->addSpotColor('Custom Yellow', $color_custom_yellow);
|
||||
|
||||
$style2 = [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 0,
|
||||
'lineJoin' => 0,
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'white',
|
||||
'fillColor' => 'white',
|
||||
];
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getStyleCmd($style2));
|
||||
|
||||
// Color Registration Bars with spot colors
|
||||
|
||||
$colregspot = $pdf->graph->getColorRegistrationBar($posx - 20, $posy + 80, 100, 10, true, [
|
||||
['black'],
|
||||
['red'],
|
||||
['green'],
|
||||
['blue'],
|
||||
['Custom Dark Green'],
|
||||
['Custom Light Yellow'],
|
||||
['Custom Black'],
|
||||
['Custom Red'],
|
||||
['Custom Green'],
|
||||
['Custom Blue'],
|
||||
['Custom Yellow'],
|
||||
]);
|
||||
$pdf->page->addContent($colregspot);
|
||||
|
||||
$colreg1 = $pdf->graph->getColorRegistrationBar($posx, $posy, 40, 40, false);
|
||||
$pdf->page->addContent($colreg1);
|
||||
|
||||
$colreg2 = $pdf->graph->getColorRegistrationBar($posx + 40, $posy, 40, 40, true);
|
||||
$pdf->page->addContent($colreg2);
|
||||
|
||||
$barcols = [
|
||||
['black'],
|
||||
['white'],
|
||||
['red'],
|
||||
['green'],
|
||||
['blue'],
|
||||
['cyan'],
|
||||
['magenta'],
|
||||
['yellow'],
|
||||
['gray'],
|
||||
['black'],
|
||||
];
|
||||
|
||||
$colreg3 = $pdf->graph->getColorRegistrationBar($posx, $posy + 45, 80, 5, true, $barcols);
|
||||
$pdf->page->addContent($colreg3);
|
||||
|
||||
$colreg4 = $pdf->graph->getColorRegistrationBar($posx + 85, $posy, 5, 50, false, $barcols);
|
||||
$pdf->page->addContent($colreg4);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,523 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E036_graphic_methods.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 036');
|
||||
$pdf->setTitle('Graphic Methods');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf graphic methods lines curves polygons shapes');
|
||||
$pdf->setPDFFilename('036_graphic_methods.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
$style1 = [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [5, 2, 1, 2],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'red',
|
||||
'fillColor' => 'powderblue',
|
||||
];
|
||||
|
||||
$style2 = [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'green',
|
||||
'fillColor' => 'powderblue',
|
||||
];
|
||||
|
||||
$style3 = [
|
||||
'lineWidth' => 1,
|
||||
'lineCap' => 'round',
|
||||
'lineJoin' => 'round',
|
||||
'dashArray' => [6, 2],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'blue',
|
||||
'fillColor' => 'powderblue',
|
||||
];
|
||||
|
||||
$style4 = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'miterLimit' => 0.5,
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'black',
|
||||
'fillColor' => 'aliceblue',
|
||||
],
|
||||
// TOP
|
||||
0 => [
|
||||
'lineWidth' => 0.25,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'red',
|
||||
'fillColor' => 'powderblue',
|
||||
],
|
||||
// RIGHT
|
||||
1 => [
|
||||
'lineWidth' => 0.25,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'green',
|
||||
'fillColor' => 'powderblue',
|
||||
],
|
||||
// BOTTOM
|
||||
2 => [
|
||||
'lineWidth' => 0.50,
|
||||
'lineCap' => 'round',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'blue',
|
||||
'fillColor' => 'powderblue',
|
||||
],
|
||||
// LEFT
|
||||
3 => [
|
||||
'lineWidth' => 0.75,
|
||||
'lineCap' => 'square',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [6, 3, 2, 3],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'yellow',
|
||||
'fillColor' => 'powderblue',
|
||||
],
|
||||
];
|
||||
|
||||
$style5 = [
|
||||
'lineWidth' => 0.25,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'darkblue',
|
||||
'fillColor' => 'mistyrose',
|
||||
];
|
||||
|
||||
$style6 = [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [3, 3],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'green',
|
||||
'fillColor' => 'powderblue',
|
||||
];
|
||||
|
||||
$style7 = [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'darkorange',
|
||||
'fillColor' => 'palegreen',
|
||||
];
|
||||
|
||||
// ----------
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
|
||||
$titleHtml = <<<HTML
|
||||
<h1 style="font-size:16pt; color:#003366;">Graphic Methods</h1>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
This example presents a compact visual overview of the drawing primitives available in tc-lib-pdf,
|
||||
including pie sectors, ellipses, lines, rectangles, curves, polygons, regular polygons, star polygons,
|
||||
rounded rectangles, and arrow styles.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $titleHtml, posx: 15, posy: 15, width: 180);
|
||||
|
||||
$xc = 105;
|
||||
$yc = 150;
|
||||
$r = 50;
|
||||
|
||||
$pie1 = $pdf->graph->getPieSector($xc, $yc, $r, 20, 120, 'FD', $style5, 2);
|
||||
$pdf->page->addContent($pie1);
|
||||
|
||||
$pie2 = $pdf->graph->getPieSector($xc, $yc, $r, 120, 250, 'FD', $style6, 2);
|
||||
$pdf->page->addContent($pie2);
|
||||
|
||||
$pie3 = $pdf->graph->getPieSector($xc, $yc, $r, 250, 20, 'FD', $style7, 2);
|
||||
$pdf->page->addContent($pie3);
|
||||
|
||||
// ----------
|
||||
|
||||
$page02 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Ellipse', link: '', level: 1);
|
||||
|
||||
// center of ellipse
|
||||
$xc = 100;
|
||||
$yc = 100;
|
||||
// X Y axis
|
||||
$arc1 = $pdf->graph->getLine($xc - 50, $yc, $xc + 50, $yc, $style1);
|
||||
$pdf->page->addContent($arc1);
|
||||
|
||||
$arc2 = $pdf->graph->getLine($xc, $yc - 50, $xc, $yc + 50, $style2);
|
||||
$pdf->page->addContent($arc2);
|
||||
|
||||
// ellipse axis
|
||||
$arc3 = $pdf->graph->getLine($xc - 50, $yc - 50, $xc + 50, $yc + 50, $style3);
|
||||
$pdf->page->addContent($arc3);
|
||||
|
||||
$arc4 = $pdf->graph->getLine($xc - 50, $yc + 50, $xc + 50, $yc - 50, $style5);
|
||||
$pdf->page->addContent($arc4);
|
||||
|
||||
// ellipse
|
||||
$arc5 = $pdf->graph->getEllipse($xc, $yc, 30, 15, 45, 0, 360, 'D', $style6, 2);
|
||||
$pdf->page->addContent($arc5);
|
||||
|
||||
// ellipse arc
|
||||
$arc6 = $pdf->graph->getEllipse($xc, $yc, 30, 15, 45, 45, 90, 'D', $style7, 2);
|
||||
$pdf->page->addContent($arc6);
|
||||
|
||||
// ----------
|
||||
|
||||
$page03 = $pdf->addPage();
|
||||
|
||||
// Line
|
||||
|
||||
$line1 = $pdf->graph->getLine(5, 10, 80, 30, $style1);
|
||||
$pdf->page->addContent($line1);
|
||||
|
||||
$line2 = $pdf->graph->getLine(5, 10, 5, 30, $style2);
|
||||
$pdf->page->addContent($line2);
|
||||
|
||||
$line3 = $pdf->graph->getLine(5, 10, 80, 10, $style3);
|
||||
$pdf->page->addContent($line3);
|
||||
|
||||
// Rectangle
|
||||
|
||||
$rect1 = $pdf->graph->getRect(100, 10, 40, 20, 'DF', $style4);
|
||||
$pdf->page->addContent($rect1);
|
||||
|
||||
$rect2 = $pdf->graph->getRect(145, 10, 40, 20, 'D', [
|
||||
'all' => $style3,
|
||||
]);
|
||||
$pdf->page->addContent($rect2);
|
||||
|
||||
// Curve
|
||||
|
||||
$curve1 = $pdf->graph->getCurve(5, 40, 30, 55, 70, 45, 60, 75, '', $style6);
|
||||
$pdf->page->addContent($curve1);
|
||||
|
||||
$curve2 = $pdf->graph->getCurve(80, 40, 70, 75, 150, 45, 100, 75, 'F', $style6);
|
||||
$pdf->page->addContent($curve2);
|
||||
|
||||
$curve3 = $pdf->graph->getCurve(140, 40, 150, 55, 180, 45, 200, 75, 'DF', $style6);
|
||||
$pdf->page->addContent($curve3);
|
||||
|
||||
// Circle
|
||||
|
||||
$circle1 = $pdf->graph->getCircle(25, 105, 20);
|
||||
$pdf->page->addContent($circle1);
|
||||
|
||||
$circle2 = $pdf->graph->getCircle(25, 105, 10, 90, 180, '', $style7);
|
||||
$pdf->page->addContent($circle2);
|
||||
|
||||
$circle3 = $pdf->graph->getCircle(25, 105, 10, 270, 360, 'F');
|
||||
$pdf->page->addContent($circle3);
|
||||
|
||||
$circle4 = $pdf->graph->getCircle(25, 105, 10, 270, 360, 'C', $style7);
|
||||
$pdf->page->addContent($circle4);
|
||||
|
||||
// Ellipse
|
||||
|
||||
$ellipse1 = $pdf->graph->getEllipse(100, 103, 40, 20);
|
||||
$pdf->page->addContent($ellipse1);
|
||||
|
||||
$ellipse2 = $pdf->graph->getEllipse(100, 105, 20, 10, 0, 90, 180, '', $style7);
|
||||
$pdf->page->addContent($ellipse2);
|
||||
|
||||
$ellipse3 = $pdf->graph->getEllipse(100, 105, 20, 10, 0, 270, 360, 'DF', $style7);
|
||||
$pdf->page->addContent($ellipse3);
|
||||
|
||||
$ellipse4 = $pdf->graph->getEllipse(175, 103, 30, 15, 45);
|
||||
$pdf->page->addContent($ellipse4);
|
||||
|
||||
$ellipse5 = $pdf->graph->getEllipse(175, 105, 15, 7.50, 45, 90, 180, '', $style7);
|
||||
$pdf->page->addContent($ellipse5);
|
||||
|
||||
$ellipse6 = $pdf->graph->getEllipse(175, 105, 15, 7.50, 45, 270, 360, 'F', $style7, 4);
|
||||
$pdf->page->addContent($ellipse6);
|
||||
|
||||
// Polygon
|
||||
|
||||
$polygon1 = $pdf->graph->getPolygon([5, 135, 45, 135, 15, 165], 's');
|
||||
$pdf->page->addContent($polygon1);
|
||||
|
||||
$polygon2 = $pdf->graph->getPolygon([60, 135, 80, 135, 80, 155, 70, 165, 50, 155], 'DF', [
|
||||
$style6,
|
||||
$style7,
|
||||
$style7,
|
||||
$style6,
|
||||
$style6,
|
||||
]);
|
||||
$pdf->page->addContent($polygon2);
|
||||
|
||||
$polygon3 = $pdf->graph->getPolygon([120, 135, 140, 135, 150, 155, 110, 155], 'D', [
|
||||
$style5,
|
||||
$style6,
|
||||
$style7,
|
||||
$style6,
|
||||
]);
|
||||
$pdf->page->addContent($polygon3);
|
||||
|
||||
$polygon4 = $pdf->graph->getPolygon([160, 135, 190, 155, 170, 155, 200, 160, 160, 165], 'DF', [
|
||||
'all' => $style6,
|
||||
]);
|
||||
$pdf->page->addContent($polygon4);
|
||||
|
||||
$polygon5 = $pdf->graph->getPolygon([80, 165, 90, 160, 100, 165, 110, 160, 120, 165, 130, 160, 140, 165], 'D', [
|
||||
'all' => $style1,
|
||||
]);
|
||||
$pdf->page->addContent($polygon5);
|
||||
|
||||
// Regular Polygon
|
||||
|
||||
$regpoly1 = $pdf->graph->getRegularPolygon(
|
||||
20,
|
||||
190,
|
||||
15,
|
||||
6,
|
||||
0,
|
||||
'b',
|
||||
[
|
||||
'all' => $style6,
|
||||
],
|
||||
's',
|
||||
$style5,
|
||||
);
|
||||
$pdf->page->addContent($regpoly1);
|
||||
|
||||
$regpoly2 = $pdf->graph->getRegularPolygon(55, 190, 15, 6, 0, 's');
|
||||
$pdf->page->addContent($regpoly2);
|
||||
|
||||
$regpoly3 = $pdf->graph->getRegularPolygon(55, 190, 10, 6, 45, 'DF', [
|
||||
$style6,
|
||||
$style5,
|
||||
$style7,
|
||||
$style5,
|
||||
$style7,
|
||||
$style7,
|
||||
]);
|
||||
$pdf->page->addContent($regpoly3);
|
||||
|
||||
$regpoly4 = $pdf->graph->getRegularPolygon(
|
||||
90,
|
||||
190,
|
||||
15,
|
||||
3,
|
||||
0,
|
||||
'b',
|
||||
[
|
||||
'all' => $style5,
|
||||
],
|
||||
'F',
|
||||
$style6,
|
||||
);
|
||||
$pdf->page->addContent($regpoly4);
|
||||
|
||||
$regpoly5 = $pdf->graph->getRegularPolygon(
|
||||
125,
|
||||
190,
|
||||
15,
|
||||
4,
|
||||
30,
|
||||
'b',
|
||||
[
|
||||
'all' => $style5,
|
||||
],
|
||||
's',
|
||||
$style1,
|
||||
);
|
||||
$pdf->page->addContent($regpoly5);
|
||||
|
||||
$regpoly6 = $pdf->graph->getRegularPolygon(160, 190, 15, 10, 0, 's');
|
||||
$pdf->page->addContent($regpoly6);
|
||||
|
||||
// Star Polygon
|
||||
|
||||
$startpoly1 = $pdf->graph->getStarPolygon(
|
||||
20,
|
||||
230,
|
||||
15,
|
||||
20,
|
||||
3,
|
||||
0,
|
||||
's',
|
||||
[
|
||||
'all' => $style2,
|
||||
],
|
||||
'b',
|
||||
$style5,
|
||||
);
|
||||
$pdf->page->addContent($startpoly1);
|
||||
|
||||
$startpoly2 = $pdf->graph->getStarPolygon(55, 230, 15, 12, 5, 15, 's');
|
||||
$pdf->page->addContent($startpoly2);
|
||||
|
||||
$startpoly3 = $pdf->graph->getStarPolygon(
|
||||
55,
|
||||
230,
|
||||
7,
|
||||
12,
|
||||
5,
|
||||
45,
|
||||
'b',
|
||||
[
|
||||
'all' => $style7,
|
||||
],
|
||||
'F',
|
||||
$style6,
|
||||
);
|
||||
$pdf->page->addContent($startpoly3);
|
||||
|
||||
$startpoly4 = $pdf->graph->getStarPolygon(
|
||||
90,
|
||||
230,
|
||||
15,
|
||||
20,
|
||||
6,
|
||||
0,
|
||||
's',
|
||||
[
|
||||
'all' => $style5,
|
||||
],
|
||||
'F',
|
||||
$style6,
|
||||
);
|
||||
$pdf->page->addContent($startpoly4);
|
||||
|
||||
$startpoly5 = $pdf->graph->getStarPolygon(
|
||||
125,
|
||||
230,
|
||||
15,
|
||||
5,
|
||||
2,
|
||||
30,
|
||||
's',
|
||||
[
|
||||
'all' => $style5,
|
||||
],
|
||||
's',
|
||||
$style6,
|
||||
);
|
||||
$pdf->page->addContent($startpoly5);
|
||||
|
||||
$startpoly6 = $pdf->graph->getStarPolygon(160, 230, 15, 10, 3, 0, 's');
|
||||
$pdf->page->addContent($startpoly6);
|
||||
|
||||
$startpoly7 = $pdf->graph->getStarPolygon(160, 230, 7, 50, 26, 10, 's');
|
||||
$pdf->page->addContent($startpoly7);
|
||||
|
||||
// Rounded Rectangle
|
||||
|
||||
$roundrect1 = $pdf->graph->getRoundedRect(5, 255, 40, 30, 3.50, 3.50, '1111', 'DF');
|
||||
$pdf->page->addContent($roundrect1);
|
||||
|
||||
$roundrect2 = $pdf->graph->getRoundedRect(50, 255, 40, 30, 6.50, 6.50, '1000', 'b');
|
||||
$pdf->page->addContent($roundrect2);
|
||||
|
||||
$roundrect3 = $pdf->graph->getRoundedRect(95, 255, 40, 30, 10.0, 5.0, '1111', 's', $style6);
|
||||
$pdf->page->addContent($roundrect3);
|
||||
|
||||
$roundrect4 = $pdf->graph->getRoundedRect(140, 255, 40, 30, 8.0, 8.0, '0101', 'DF', $style6);
|
||||
$pdf->page->addContent($roundrect4);
|
||||
|
||||
// Arrows
|
||||
|
||||
$arrow1 = $pdf->graph->getArrow(200, 280, 185, 266, 0, 5, 15);
|
||||
$pdf->page->addContent($arrow1);
|
||||
|
||||
$arrow2 = $pdf->graph->getArrow(200, 280, 190, 263, 1, 5, 15);
|
||||
$pdf->page->addContent($arrow2);
|
||||
|
||||
$arrow3 = $pdf->graph->getArrow(200, 280, 195, 261, 2, 5, 15);
|
||||
$pdf->page->addContent($arrow3);
|
||||
|
||||
$arrow4 = $pdf->graph->getArrow(200, 280, 200, 260, 3, 5, 15);
|
||||
$pdf->page->addContent($arrow4);
|
||||
|
||||
// ----------
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E037_image_methods.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 037');
|
||||
$pdf->setTitle('Image Methods');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf image methods jpeg png svg placement scaling');
|
||||
$pdf->setPDFFilename('037_image_methods.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
// Add first page
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
|
||||
$html = <<<HTML
|
||||
<h1 style="font-size:16pt; color:#003366;">Image Methods</h1>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
This example shows how to place JPEG and PNG images with different color models and transparency.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 15, width: 180);
|
||||
|
||||
$posx = 5;
|
||||
$posy = 40;
|
||||
|
||||
// Cell grid geometry: 5 columns, each sample rendered $cellw units wide.
|
||||
$cellw = 40;
|
||||
$rowh = 20;
|
||||
$cols = 5;
|
||||
|
||||
// Sample images exercising different color models and transparency.
|
||||
$samples = [
|
||||
'200x100_CMYK.jpg', // CMYK JPEG sample.
|
||||
'200x100_GRAY.jpg', // Grayscale JPEG sample.
|
||||
'200x100_GRAY.png', // Grayscale PNG sample.
|
||||
'200x100_INDEX16.png', // Indexed-color PNG with a 16-color palette.
|
||||
'200x100_INDEX256.png', // Indexed-color PNG with a 256-color palette.
|
||||
'200x100_INDEXALPHA.png', // Indexed-color PNG with alpha transparency.
|
||||
'200x100_RGB.jpg', // RGB JPEG sample.
|
||||
'200x100_RGB.png', // RGB PNG sample.
|
||||
'200x100_RGBALPHA.png', // RGB PNG with alpha transparency.
|
||||
'200x100_RGBICC.jpg', // RGB JPEG carrying an ICC color profile.
|
||||
'200x100_RGBICC.png', // RGB PNG carrying an ICC color profile.
|
||||
'200x100_RGBINT.png', // RGB PNG variant (alternate RGB image path).
|
||||
];
|
||||
|
||||
// Add Images
|
||||
//
|
||||
// Each sample is rendered preserving its original aspect ratio: only the target
|
||||
// width is provided and the matching height is computed directly from the
|
||||
// intrinsic image size by image->getImageDimensionsByKey().
|
||||
foreach ($samples as $index => $name) {
|
||||
$file = $imgdir . '/' . $name;
|
||||
|
||||
// Import the image; add() returns the image instance ID used for placement.
|
||||
$iid = $pdf->image->add($file);
|
||||
|
||||
// Resolve the cache key for the imported image.
|
||||
$key = $pdf->image->getKey($file);
|
||||
|
||||
// Derive the rendered dimensions from the intrinsic image size: a single
|
||||
// target side (width) is given and the other (height) is computed to
|
||||
// preserve the original aspect ratio.
|
||||
$dim = $pdf->image->getImageDimensionsByKey($key, $cellw);
|
||||
|
||||
$col = $index % $cols;
|
||||
$row = \intdiv($index, $cols);
|
||||
$imgx = $posx + ($col * $cellw);
|
||||
$imgy = $posy + ($row * $rowh);
|
||||
|
||||
$out = $pdf->image->getSetImage($iid, $imgx, $imgy, $dim['width'], $dim['height'], $page01['height']);
|
||||
$pdf->page->addContent($out);
|
||||
}
|
||||
|
||||
// getImageDimensionsByKey() supports additional resolution modes, for example:
|
||||
// $pdf->image->getImageDimensionsByKey($key); // original pixel size
|
||||
// $pdf->image->getImageDimensionsByKey($key, 0, 30); // derive width from height
|
||||
// $pdf->image->getImageDimensionsByKey($key, 40, 40, true); // scale to fit a 40x40 box
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E038_image_clipping.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 038');
|
||||
$pdf->setTitle('Image Clipping');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf image clipping masks clipping paths');
|
||||
$pdf->setPDFFilename('038_image_clipping.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
$page10 = $pdf->addPage();
|
||||
|
||||
$html = <<<HTML
|
||||
<h1 style="font-size:16pt; color:#003366;">Image Clipping</h1>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Demonstrates how to apply a clipping mask to an image using a star polygon path.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 15, width: 180);
|
||||
|
||||
// Clipping Mask
|
||||
|
||||
$posx = 80;
|
||||
$posy = 100;
|
||||
|
||||
$cnz = $pdf->graph->getStartTransform();
|
||||
$cnz .= $pdf->graph->getStarPolygon($posx, $posy, 40, 10, 3, 0, 'CNZ');
|
||||
$clipimg = $pdf->image->add($imgdir . '/200x100_CMYK.jpg');
|
||||
$cnz .= $pdf->image->getSetImage($clipimg, $posx - 40, $posy - 40, 80, 80, $page10['height']);
|
||||
$cnz .= $pdf->graph->getStopTransform();
|
||||
|
||||
$pdf->page->addContent($cnz);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,588 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E039_text_methods.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 039');
|
||||
$pdf->setTitle('Text Methods');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf text methods alignment spacing writing');
|
||||
$pdf->setPDFFilename('039_text_methods.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'Text', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: '');
|
||||
|
||||
// Add an internal link to this page
|
||||
$page01_link = $pdf->addInternalLink();
|
||||
|
||||
$styletxt = [
|
||||
'lineWidth' => 0.25,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'red',
|
||||
'fillColor' => 'black',
|
||||
];
|
||||
|
||||
$pdf->graph->add($styletxt);
|
||||
|
||||
$bfont2 = $pdf->font->insert($pdf->pon, 'times', 'BI', 24);
|
||||
|
||||
$pdf->page->addContent($bfont2['out']);
|
||||
// alternative to set the current font (last entry in the font stack):
|
||||
// $pdf->page->addContent($pdf->font->getOutCurrentFont());
|
||||
|
||||
// Add text
|
||||
$txt = $pdf->getTextLine(
|
||||
txt: 'Test PDF text with justification (stretching) % %% %%%',
|
||||
posx: 0,
|
||||
posy: $pdf->toUnit($bfont2['ascent']),
|
||||
width: $page01['width'],
|
||||
);
|
||||
|
||||
$pdf->page->addContent($txt);
|
||||
|
||||
$bbox = $pdf->getLastBBox();
|
||||
|
||||
// Add text
|
||||
$txt2 = $pdf->getTextLine(
|
||||
txt: 'Link to https://tcpdf.org',
|
||||
posx: 15,
|
||||
posy: $bbox['y'] + $bbox['h'] + $pdf->toUnit($bfont2['ascent']),
|
||||
width: 0,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
txtanchor: 'S',
|
||||
shadow: [
|
||||
'xoffset' => 0.5,
|
||||
'yoffset' => 0.5,
|
||||
'opacity' => 0.5,
|
||||
'mode' => 'Normal',
|
||||
'color' => 'red',
|
||||
],
|
||||
);
|
||||
$pdf->page->addContent($txt2);
|
||||
|
||||
// get the coordinates of the box containing the last added text string.
|
||||
$bbox = $pdf->getLastBBox();
|
||||
|
||||
$aoid1 = $pdf->setLink(
|
||||
posx: $bbox['x'],
|
||||
posy: $bbox['y'],
|
||||
width: $bbox['w'],
|
||||
height: $bbox['h'],
|
||||
link: 'https://tcpdf.org',
|
||||
);
|
||||
$pdf->page->addAnnotRef($aoid1);
|
||||
|
||||
// -----------------------------------------------
|
||||
|
||||
// add a text column with automatic line breaking
|
||||
|
||||
$bfont3 = $pdf->font->insert($pdf->pon, 'courier', '', 14);
|
||||
$pdf->page->addContent($bfont3['out']);
|
||||
|
||||
$txt3 =
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
|
||||
. "\n"
|
||||
. 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
|
||||
|
||||
$col = $pdf->color->getPdfColor('blue');
|
||||
$pdf->page->addContent($col);
|
||||
|
||||
// single block of text
|
||||
$txtbox = $pdf->getTextCell(
|
||||
txt: $txt3,
|
||||
posx: 20,
|
||||
posy: 30,
|
||||
width: 150,
|
||||
height: 0,
|
||||
offset: 15,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
$pdf->page->addContent($txtbox);
|
||||
|
||||
$col = $pdf->color->getPdfColor('black');
|
||||
$pdf->page->addContent($col);
|
||||
|
||||
$bfont4 = $pdf->font->insert($pdf->pon, 'freeserif', 'I', 12);
|
||||
$pdf->page->addContent($bfont4['out']);
|
||||
|
||||
$pdf->setDefaultCellPadding(top: 2, right: 2, bottom: 2, left: 2);
|
||||
|
||||
// Text cell
|
||||
$style_cell = [
|
||||
'all' => [
|
||||
'lineWidth' => 1,
|
||||
'lineCap' => 'round',
|
||||
'lineJoin' => 'round',
|
||||
'miterLimit' => 1,
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'green',
|
||||
'fillColor' => 'yellow',
|
||||
],
|
||||
];
|
||||
|
||||
$pdf->setDefaultCellBorderPos(borderpos: $pdf::BORDERPOS_DEFAULT);
|
||||
$txtcell1 = $pdf->getTextCell(
|
||||
txt: 'DEFAULT',
|
||||
posx: 20,
|
||||
posy: 100,
|
||||
width: 0,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
cell: null,
|
||||
styles: $style_cell,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
$pdf->page->addContent($txtcell1);
|
||||
|
||||
$pdf->setDefaultCellBorderPos(borderpos: $pdf::BORDERPOS_EXTERNAL);
|
||||
$txtcell2 = $pdf->getTextCell(
|
||||
txt: 'EXTERNAL',
|
||||
posx: 49,
|
||||
posy: 100,
|
||||
width: 0,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
cell: null,
|
||||
styles: $style_cell,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
$pdf->page->addContent($txtcell2);
|
||||
|
||||
$pdf->setDefaultCellBorderPos(borderpos: $pdf::BORDERPOS_INTERNAL);
|
||||
$txtcell2 = $pdf->getTextCell(
|
||||
txt: 'INTERNAL',
|
||||
posx: 80,
|
||||
posy: 100,
|
||||
width: 0,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
cell: null,
|
||||
styles: $style_cell,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
$pdf->page->addContent($txtcell2);
|
||||
|
||||
$defbstyle = [
|
||||
'lineWidth' => $pdf->toUnit(1),
|
||||
'lineCap' => 'square',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#333333',
|
||||
'fillColor' => '#cccccc',
|
||||
];
|
||||
$bstyle = [
|
||||
'all' => $defbstyle,
|
||||
0 => $defbstyle, // TOP
|
||||
1 => $defbstyle, // RIGHT
|
||||
2 => $defbstyle, // BOTTOM
|
||||
3 => $defbstyle, // LEFT
|
||||
];
|
||||
$bstyle[0]['lineColor'] = $bstyle[3]['lineColor'] = '#e7e7e7';
|
||||
|
||||
$pdf->setDefaultCellBorderPos(borderpos: $pdf::BORDERPOS_DEFAULT);
|
||||
$txtcell3 = $pdf->getTextCell(
|
||||
txt: 'BUTTON',
|
||||
posx: 120,
|
||||
posy: 100,
|
||||
width: 0,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
cell: null,
|
||||
styles: $bstyle,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
$pdf->page->addContent($txtcell3);
|
||||
|
||||
$pdf->setDefaultCellBorderPos(borderpos: $pdf::BORDERPOS_DEFAULT);
|
||||
|
||||
$txtcell2 = $pdf->getTextCell(
|
||||
txt: $txt3,
|
||||
posx: 20,
|
||||
posy: 120,
|
||||
width: 150,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
cell: null,
|
||||
styles: $style_cell,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
$pdf->page->addContent($txtcell2);
|
||||
|
||||
$bfont4 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 14);
|
||||
$pdf->page->addContent($bfont4['out']);
|
||||
|
||||
$pdf->setDefaultCellPadding(top: 2, right: 2, bottom: 2, left: 2);
|
||||
|
||||
$style_cell_b = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'round',
|
||||
'lineJoin' => 'round',
|
||||
'miterLimit' => 0.5,
|
||||
'dashArray' => [0, 1],
|
||||
'dashPhase' => 2,
|
||||
'lineColor' => 'red',
|
||||
],
|
||||
];
|
||||
|
||||
// block of text between two page regions
|
||||
$pdf->addTextCell(
|
||||
txt: "\u{27A0}" . $txt3,
|
||||
pid: -1,
|
||||
posx: 20,
|
||||
posy: 165,
|
||||
width: 150,
|
||||
height: 0,
|
||||
offset: 15,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
cell: null,
|
||||
styles: $style_cell_b,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
|
||||
$txt4 = 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?';
|
||||
|
||||
$txt5 = 'At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.';
|
||||
|
||||
$pdf->enableZeroWidthBreakPoints(true);
|
||||
$pdf->addTextCell(
|
||||
txt: 'TEST-TEXT-ENABLE-AUTO-BREAK-POINTS',
|
||||
pid: -1,
|
||||
posx: 20,
|
||||
posy: 233,
|
||||
width: 85,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: $style_cell,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
|
||||
$pdf->enableZeroWidthBreakPoints(false);
|
||||
$pdf->addTextCell(
|
||||
txt: 'TEST-TEXT-DISABLE-AUTO-BREAK-POINTS',
|
||||
pid: -1,
|
||||
posx: 20,
|
||||
posy: 252,
|
||||
width: 85,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: $style_cell,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
|
||||
// Hyphenation example
|
||||
// TEX hyphenation patterns can be downloaded from:
|
||||
// https://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/tex
|
||||
//
|
||||
//$hyphen_patterns = $pdf->loadTexHyphenPatterns('../../RESOURCES/hyph-la-x-classic.tex');
|
||||
//$pdf->setTexHyphenPatterns($hyphen_patterns);
|
||||
|
||||
// block of text between two page regions
|
||||
$pdf->addTextCell(
|
||||
txt: $txt3 . "\n" . $txt4 . "\n" . $txt5,
|
||||
pid: -1,
|
||||
posx: 20,
|
||||
posy: 265,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 15,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
cell: null,
|
||||
styles: $style_cell,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: 'overline, linethrough and underline',
|
||||
pid: -1,
|
||||
posx: 15,
|
||||
posy: 50,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: true,
|
||||
linethrough: true,
|
||||
overline: true,
|
||||
clip: false,
|
||||
drawcell: false,
|
||||
forcedir: \Com\Tecnick\Unicode\TextDirection::Auto,
|
||||
shadow: null,
|
||||
);
|
||||
|
||||
$pdf->addTextCell(
|
||||
txt: 'addTextCell()' . PHP_EOL . 'First line.' . PHP_EOL . 'Second Line.',
|
||||
posx: 15,
|
||||
posy: 70,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'getTextCell()' . PHP_EOL . 'First line.' . PHP_EOL . 'Second Line.',
|
||||
posx: 15,
|
||||
posy: 90,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E040_annotation_form.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 040');
|
||||
$pdf->setTitle('Annotation Form Widgets');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf annotations form widgets acroform fields');
|
||||
$pdf->setPDFFilename('040_annotation_form.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
// Annotation Form Fields
|
||||
|
||||
$page1 = $pdf->addPage();
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 12);
|
||||
$pdf->page->addContent($bfont1['out']);
|
||||
|
||||
$html = <<<HTML
|
||||
<h1 style="font-size:16pt; color:#003366;">Annotation Form Example</h1>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
This page demonstrates interactive PDF form fields including text input,
|
||||
radio buttons, a checkbox, combo and list boxes, plus reset, print, and
|
||||
submit actions.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 15, width: 180);
|
||||
|
||||
$posx = 80;
|
||||
$posy = 100;
|
||||
|
||||
$labelWidth = 62;
|
||||
$labelX = 15;
|
||||
$labelStyle = 'font-size:9pt; color:#333333; text-align:right;';
|
||||
|
||||
// text
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">Text Input:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$fftextid = $pdf->addFFText('test_text', $posx, $posy, 50, 5);
|
||||
$pdf->page->addAnnotRef($fftextid);
|
||||
|
||||
// radiobuttons
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">Radio – Option One:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy + 10,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">Radio – Option Two:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy + 15,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">Radio – Option Three:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy + 20,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$ffrbid1 = $pdf->addFFRadioButton(name: 'test_radiobutton', posx: $posx, posy: $posy + 10, width: 5, onvalue: 'one');
|
||||
$ffrbid2 = $pdf->addFFRadioButton(
|
||||
name: 'test_radiobutton',
|
||||
posx: $posx,
|
||||
posy: $posy + 15,
|
||||
width: 5,
|
||||
onvalue: 'two',
|
||||
checked: true,
|
||||
);
|
||||
$ffrbid3 = $pdf->addFFRadioButton(name: 'test_radiobutton', posx: $posx, posy: $posy + 20, width: 5, onvalue: 'three');
|
||||
$pdf->page->addAnnotRef($ffrbid1);
|
||||
$pdf->page->addAnnotRef($ffrbid2);
|
||||
$pdf->page->addAnnotRef($ffrbid3);
|
||||
|
||||
// checkbox
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">Checkbox:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy + 30,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$ffckbxid1 = $pdf->addFFCheckBox('test_checkbox', $posx, $posy + 30, 5);
|
||||
$pdf->page->addAnnotRef($ffckbxid1);
|
||||
|
||||
// combobox
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">Combo Box:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy + 40,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$ffcmbxid1 = $pdf->addFFComboBox('test_combobox', $posx, $posy + 40, 50, 5, [
|
||||
['0', 'one'],
|
||||
['1', 'two'],
|
||||
['2', 'three'],
|
||||
]);
|
||||
$pdf->page->addAnnotRef($ffcmbxid1);
|
||||
|
||||
// listbox
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">List Box:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy + 50,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$fflsbxid1 = $pdf->addFFListBox(
|
||||
'test_listbox',
|
||||
$posx,
|
||||
$posy + 50,
|
||||
50,
|
||||
15,
|
||||
['one', 'two', 'three'],
|
||||
['subtype' => 'Widget'],
|
||||
['multipleSelection' => 'true'],
|
||||
);
|
||||
$pdf->page->addAnnotRef($fflsbxid1);
|
||||
|
||||
// button - reset form
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p style="' . $labelStyle . '">Actions:</p>',
|
||||
posx: $labelX,
|
||||
posy: $posy + 70,
|
||||
width: $labelWidth,
|
||||
height: 5,
|
||||
);
|
||||
$ffbtnid1 = $pdf->addFFButton(
|
||||
name: 'reset',
|
||||
posx: $posx,
|
||||
posy: $posy + 70,
|
||||
width: 20,
|
||||
height: 5,
|
||||
caption: 'Reset',
|
||||
action: ['S' => 'ResetForm'],
|
||||
opt: ['subtype' => 'Widget'],
|
||||
jsp: [
|
||||
'lineWidth' => 2,
|
||||
'borderStyle' => 'beveled',
|
||||
'fillColor' => '#80c4ff',
|
||||
'strokeColor' => '#404040',
|
||||
],
|
||||
);
|
||||
$pdf->page->addAnnotRef($ffbtnid1);
|
||||
|
||||
// button - print document
|
||||
$ffbtnid2 = $pdf->addFFButton(
|
||||
name: 'print',
|
||||
posx: $posx + 20,
|
||||
posy: $posy + 70,
|
||||
width: 20,
|
||||
height: 5,
|
||||
caption: 'Print',
|
||||
action: 'Print()',
|
||||
opt: ['subtype' => 'Widget'],
|
||||
jsp: [
|
||||
'lineWidth' => 2,
|
||||
'borderStyle' => 'beveled',
|
||||
'fillColor' => '#80c4ff',
|
||||
'strokeColor' => '#404040',
|
||||
],
|
||||
);
|
||||
$pdf->page->addAnnotRef($ffbtnid2);
|
||||
|
||||
// button - submit form
|
||||
$ffbtnid3 = $pdf->addFFButton(
|
||||
name: 'submit',
|
||||
posx: $posx + 40,
|
||||
posy: $posy + 70,
|
||||
width: 20,
|
||||
height: 5,
|
||||
caption: 'Submit',
|
||||
action: [
|
||||
'S' => 'SubmitForm',
|
||||
'F' => 'http://localhost/printvars.php',
|
||||
'Flags' => ['ExportFormat'],
|
||||
],
|
||||
opt: ['subtype' => 'Widget'],
|
||||
jsp: [
|
||||
'lineWidth' => 2,
|
||||
'borderStyle' => 'beveled',
|
||||
'fillColor' => '#80c4ff',
|
||||
'strokeColor' => '#404040',
|
||||
],
|
||||
);
|
||||
$pdf->page->addAnnotRef($ffbtnid3);
|
||||
|
||||
// JavaScript form validation functions
|
||||
$formjs = <<<EOD
|
||||
function CheckField(name,message) {
|
||||
var f = getField(name);
|
||||
if(f.value == '') {
|
||||
app.alert(message);
|
||||
f.setFocus();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function Print() {
|
||||
if(!CheckField('test_text','test_text is mandatory')) {return;}
|
||||
print();
|
||||
}
|
||||
EOD;
|
||||
|
||||
// Add raw JavaScript code
|
||||
$pdf->appendRawJavaScript(script: $formjs);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E041_layers_visibility.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 041');
|
||||
$pdf->setTitle('Layer Visibility (OCG)');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf layers visibility OCG optional content groups');
|
||||
$pdf->setPDFFilename('041_layers_visibility.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 14);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
// Layers
|
||||
|
||||
$page1 = $pdf->addPage();
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Layers and Optional Content Groups',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 8,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'This page contains objects assigned to different visibility layers.',
|
||||
posx: 15,
|
||||
posy: 28,
|
||||
width: 180,
|
||||
height: 6,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell('Always visible text', 15, 40, 120, 7, 0, 0, 'T', 'L', drawcell: true));
|
||||
|
||||
$lyrScreen = $pdf->newLayer(name: 'screen_only', intent: ['view' => true], print: false, view: true, lock: false);
|
||||
$pdf->page->addContent($lyrScreen);
|
||||
$pdf->page->addContent($pdf->getTextCell('Screen-only layer content', 15, 54, 120, 7, 0, 0, 'T', 'L', drawcell: true));
|
||||
$pdf->page->addContent($pdf->closeLayer());
|
||||
|
||||
$lyrPrint = $pdf->newLayer(name: 'print_only', intent: ['design' => true], print: true, view: false, lock: false);
|
||||
$pdf->page->addContent($lyrPrint);
|
||||
$pdf->page->addContent($pdf->getTextCell('Print-only layer content', 15, 66, 120, 7, 0, 0, 'T', 'L', drawcell: true));
|
||||
$pdf->page->addContent($pdf->closeLayer());
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Viewer support for layer toggles varies by PDF reader.',
|
||||
posx: 15,
|
||||
posy: 82,
|
||||
width: 180,
|
||||
height: 6,
|
||||
));
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E042_html_form.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 042');
|
||||
$pdf->setTitle('HTML Form Elements');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf html forms input select textarea rendering');
|
||||
$pdf->setPDFFilename('042_html_form.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
// HTML G
|
||||
|
||||
$pageV07 = $pdf->addPage();
|
||||
|
||||
$html_07 = <<<EOD
|
||||
<h1>XHTML Form Example</h1>
|
||||
<form method="post" action="http://localhost/printvars.php" enctype="multipart/form-data">
|
||||
<label for="name">name:</label> <input type="text" name="name" value="" size="20" maxlength="30" /><br />
|
||||
<label for="password">password:</label> <input type="password" name="password" value="" size="20" maxlength="30" /><br /><br />
|
||||
<label for="infile">file:</label> <input type="file" name="userfile" size="20" /><br /><br />
|
||||
<input type="checkbox" name="agree" value="1" checked="checked" /> <label for="agree">I agree </label><br /><br />
|
||||
<input type="radio" name="radioquestion" id="rqa" value="1" /> <label for="rqa">one</label><br />
|
||||
<input type="radio" name="radioquestion" id="rqb" value="2" checked="checked"/> <label for="rqb">two</label><br />
|
||||
<input type="radio" name="radioquestion" id="rqc" value="3" /> <label for="rqc">three</label><br /><br />
|
||||
<label for="selection">select:</label>
|
||||
<select name="selection" size="0">
|
||||
<option value="0">zero</option>
|
||||
<option value="1">one</option>
|
||||
<option value="2">two</option>
|
||||
<option value="3">three</option>
|
||||
</select><br /><br />
|
||||
<label for="selection">select:</label>
|
||||
<select name="multiselection" size="2" multiple="multiple">
|
||||
<option value="0">zero</option>
|
||||
<option value="1">one</option>
|
||||
<option value="2">two</option>
|
||||
<option value="3">three</option>
|
||||
</select><br /><br /><br />
|
||||
<label for="text">text area:</label><br />
|
||||
<textarea cols="40" rows="3" name="text">line one
|
||||
line two</textarea><br />
|
||||
<br /><br /><br />
|
||||
<input type="reset" name="reset" value="Reset" />
|
||||
<input type="submit" name="submit" value="Submit" />
|
||||
<input type="button" name="print" value="Print" onclick="print()" />
|
||||
<input type="hidden" name="hiddenfield" value="OK" />
|
||||
<br />
|
||||
</form>
|
||||
EOD;
|
||||
|
||||
$pdf->addHTMLCell(html: $html_07, posx: 30, posy: 20);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,398 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E043_html_tables.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 043');
|
||||
$pdf->setTitle('HTML Tables');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf html tables thead tbody cell borders layout');
|
||||
$pdf->setPDFFilename('043_html_tables.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
$page1 = $pdf->addPage();
|
||||
|
||||
$subtable = '<table border="1" cellspacing="6" cellpadding="4"><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></table>';
|
||||
|
||||
$html1 = '<h2>HTML TABLES (A)</h2>
|
||||
<table border="1" cellspacing="3" cellpadding="4">
|
||||
<tr>
|
||||
<th align="center">#</th>
|
||||
<th align="right">RIGHT align</th>
|
||||
<th align="left">LEFT align</th>
|
||||
<th>4A</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td bgcolor="#cccccc" align="center" colspan="2">A1 ex<i>amp</i>le <a href="https://tcpdf.org">link</a> column span. One two tree four five six seven eight nine ten.<br />line after br<br /><small>small text</small> normal <sub>subscript</sub> normal <sup>superscript</sup> normal bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla<ol><li>first<ol><li>sublist</li><li>sublist</li></ol></li><li>second</li></ol><small color="#FF0000" bgcolor="#FFFF00">small small small small small small small small small small small small small small small small small small small small</small></td>
|
||||
<td>4B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>' . $subtable . '</td>
|
||||
<td bgcolor="#0000FF" color="yellow" align="center">A2 € € € & è è<br/>A2 € € € & è è</td>
|
||||
<td bgcolor="#FFFF00" align="left"><span color="#FF0000">Red</span> Yellow BG</td>
|
||||
<td>4C</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1A</td>
|
||||
<td rowspan="2" colspan="2" bgcolor="#FFFFCC">2AA<br />2AB<br />2AC</td>
|
||||
<td bgcolor="#FF0000">4D</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1B</td>
|
||||
<td>4E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1C</td>
|
||||
<td>2C</td>
|
||||
<td>3C</td>
|
||||
<td>4F</td>
|
||||
</tr>
|
||||
</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html1, posx: 20, posy: 10, width: 170);
|
||||
|
||||
// ----------
|
||||
|
||||
$page2 = $pdf->addPage();
|
||||
|
||||
$html2 = <<<EOF
|
||||
<!-- EXAMPLE OF CSS STYLE -->
|
||||
<style>
|
||||
table.first {
|
||||
color: #003300;
|
||||
font-family: helvetica;
|
||||
font-size: 8pt;
|
||||
border-left: 3px solid red;
|
||||
border-right: 3px solid #FF00FF;
|
||||
border-top: 3px solid green;
|
||||
border-bottom: 3px solid blue;
|
||||
background-color: #ccffcc;
|
||||
}
|
||||
td {
|
||||
border: 2px solid blue;
|
||||
background-color: #ffffee;
|
||||
}
|
||||
td.second {
|
||||
border: 2px dashed green;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2>HTML TABLES (B)</h2>
|
||||
<table class="first" cellpadding="4" cellspacing="6">
|
||||
<tr>
|
||||
<td width="30" align="center"><b>No.</b></td>
|
||||
<td width="140" align="center" bgcolor="#FFFF00"><b>XXXX</b></td>
|
||||
<td width="140" align="center"><b>XXXX</b></td>
|
||||
<td width="80" align="center"> <b>XXXX</b></td>
|
||||
<td width="80" align="center"><b>XXXX</b></td>
|
||||
<td width="45" align="center"><b>XXXX</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="30" align="center">1.</td>
|
||||
<td width="140" rowspan="6" class="second">BRDD<br />XXXX<br />XXXX<br />XXXX<br />XXXX<br />XXXX<br />XXXX<br />XXXX</td>
|
||||
<td width="140">XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX</td>
|
||||
<td align="center" width="45">XXXX<br />XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="30" align="center" rowspan="3">2.</td>
|
||||
<td width="140" rowspan="3">XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td align="center" width="45">XXXX<br />XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="80">XXXX<br />XXXX<br />XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td align="center" width="45">XXXX<br />XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="80" rowspan="2" >XXXX<br />XXXX<br />XXXX<br />XXXX<br />XXXX<br />XXXX<br />XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td align="center" width="45">XXXX<br />XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="30" align="center">3.</td>
|
||||
<td width="140">XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td align="center" width="45">XXXX<br />XXXX</td>
|
||||
</tr>
|
||||
<tr bgcolor="#FFFF80">
|
||||
<td width="30" align="center">4.</td>
|
||||
<td width="140" bgcolor="#00CC00" color="#FFFF00">XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td width="80">XXXX<br />XXXX</td>
|
||||
<td align="center" width="45">XXXX<br />XXXX</td>
|
||||
</tr>
|
||||
</table>
|
||||
EOF;
|
||||
|
||||
$pdf->addHTMLCell(html: $html2, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
$page3 = $pdf->addPage();
|
||||
|
||||
$html3 = <<<EOD
|
||||
<h2>HTML TABLES (C)</h2>
|
||||
<table cellspacing="0" cellpadding="1" border="1" style="font-size:x-small;">
|
||||
<tr>
|
||||
<td rowspan="3">COL 1 - ROW 1<br />COLSPAN 3</td>
|
||||
<td>COL 2 - ROW 1</td>
|
||||
<td>COL 3 - ROW 1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2">COL 2 - ROW 2 - COLSPAN 2<br />text line<br />text line<br />text line<br />text line</td>
|
||||
<td>COL 3 - ROW 2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COL 3 - ROW 3</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
<table cellspacing="0" cellpadding="1" border="1" style="font-size:x-small;">
|
||||
<tr>
|
||||
<td rowspan="3">COL 1 - ROW 1<br />COLSPAN 3<br />text line<br />text line<br />text line<br />text line<br />text line<br />text line</td>
|
||||
<td>COL 2 - ROW 1</td>
|
||||
<td>COL 3 - ROW 1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2">COL 2 - ROW 2 - COLSPAN 2<br />text line<br />text line<br />text line<br />text line</td>
|
||||
<td>COL 3 - ROW 2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COL 3 - ROW 3</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
<table cellspacing="0" cellpadding="1" border="1" style="font-size:x-small;">
|
||||
<tr>
|
||||
<td rowspan="3">COL 1 - ROW 1<br />COLSPAN 3<br />text line<br />text line<br />text line<br />text line<br />text line<br />text line</td>
|
||||
<td>COL 2 - ROW 1</td>
|
||||
<td>COL 3 - ROW 1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2">COL 2 - ROW 2 - COLSPAN 2<br />text line<br />text line<br />text line<br />text line</td>
|
||||
<td>COL 3 - ROW 2<br />text line<br />text line</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COL 3 - ROW 3</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
<table border="1" style="font-size:x-small;">
|
||||
<tr>
|
||||
<th rowspan="3">Left column</th>
|
||||
<th colspan="5">Heading Column Span 5</th>
|
||||
<th colspan="9">Heading Column Span 9</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th rowspan="2">Rowspan 2<br />This is some text that fills the table cell.</th>
|
||||
<th colspan="2">span 2</th>
|
||||
<th colspan="2">span 2</th>
|
||||
<th rowspan="2">2 rows</th>
|
||||
<th colspan="8">Colspan 8</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>1a</th>
|
||||
<th>2a</th>
|
||||
<th>1b</th>
|
||||
<th>2b</th>
|
||||
<th>1</th>
|
||||
<th>2</th>
|
||||
<th>3</th>
|
||||
<th>4</th>
|
||||
<th>5</th>
|
||||
<th>6</th>
|
||||
<th>7</th>
|
||||
<th>8</th>
|
||||
</tr>
|
||||
</table>
|
||||
EOD;
|
||||
|
||||
$pdf->addHTMLCell(html: $html3, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
$page4 = $pdf->addPage();
|
||||
|
||||
$html4 = '<h2>HTML TABLES (D)</h2>
|
||||
<table border="1" cellspacing="3" cellpadding="4">
|
||||
<tr>
|
||||
<td align="left"><span>1L</span> <span>Alfa</span> <span>Bravo</span> <span>Charlie</span> <span>Delta</span> <span>Echo</span> <span>Foxtrot</span> <span>Golf</span> <span>Hotel</span> <span>India</span> <span>Juliett</span> <span>Kilo</span> <span>Lima</span> <span>Mike</span> <span>November</span> <span>Oscar</span> <span>Papa</span> <span>Quebec</span> <span>Romeo</span> <span>Sierra</span> <span>Tango</span> <span>Uniform</span> <span>Victor</span> <span>Whiskey</span> <span>Xray</span> <span>Yankee</span> <span>Zulu</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><span>1C</span> <span>Alfa</span> <span>Bravo</span> <span>Charlie</span> <span>Delta</span> <span>Echo</span> <span>Foxtrot</span> <span>Golf</span> <span>Hotel</span> <span>India</span> <span>Juliett</span> <span>Kilo</span> <span>Lima</span> <span>Mike</span> <span>November</span> <span>Oscar</span> <span>Papa</span> <span>Quebec</span> <span>Romeo</span> <span>Sierra</span> <span>Tango</span> <span>Uniform</span> <span>Victor</span> <span>Whiskey</span> <span>Xray</span> <span>Yankee</span> <span>Zulu</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><span>1R</span> <span>Alfa</span> <span>Bravo</span> <span>Charlie</span> <span>Delta</span> <span>Echo</span> <span>Foxtrot</span> <span>Golf</span> <span>Hotel</span> <span>India</span> <span>Juliett</span> <span>Kilo</span> <span>Lima</span> <span>Mike</span> <span>November</span> <span>Oscar</span> <span>Papa</span> <span>Quebec</span> <span>Romeo</span> <span>Sierra</span> <span>Tango</span> <span>Uniform</span> <span>Victor</span> <span>Whiskey</span> <span>Xray</span> <span>Yankee</span> <span>Zulu</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><span>2L</span> A1 ex<i>amp</i>le <a href="https://tcpdf.org">link</a> column span. Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><span>2C</span> A1 ex<i>amp</i>le <a href="https://tcpdf.org">link</a> column span. Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><span>2R</span> A1 ex<i>amp</i>le <a href="https://tcpdf.org">link</a> column span. Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><small>3L small text</small> Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><small>3C small text</small> Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><small>3R small text</small> Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
|
||||
<table border="1" cellspacing="3" cellpadding="4">
|
||||
<tr>
|
||||
<td align="left"><img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="60" height="20" border="0" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="60" height="20" border="0" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><img src="images/tcpdf_logo.jpg" alt="TCPDF logo" width="60" height="20" border="0" /></td>
|
||||
</tr>
|
||||
</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html4, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
$html5A = '<table border="0" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<th align="left" style="font-size:32pt; color:rgba(255, 0, 0, 0.5);">
|
||||
TEST
|
||||
</th>
|
||||
</tr>
|
||||
</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html5A, posx: 20, posy: 160, width: 180);
|
||||
|
||||
$html5B = '<table border="0" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<th align="left" style="font-size:32pt; color:rgba(0, 255, 0, 0.5); padding-left:10mm;">
|
||||
TEST
|
||||
</th>
|
||||
</tr>
|
||||
</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html5B, posx: 20, posy: 160, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, 190, 210, 190, ['lineWidth' => 6, 'lineColor' => 'rgb(255, 0, 0)']));
|
||||
|
||||
$pdf->addHTMLCell(
|
||||
'<table border="0"><tr><td style="border-bottom:6mm solid rgb(255, 0, 0);"></td></tr></table>',
|
||||
0,
|
||||
195,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$page5 = $pdf->addPage();
|
||||
|
||||
// Percentage widths are resolved against the containing element:
|
||||
// an image with width:100% fills its fixed-width table cell (issue #247).
|
||||
$html6 = '<h2>HTML TABLES (E): PERCENTAGE WIDTHS</h2>
|
||||
<table style="width:100%;" border="1" cellspacing="0" cellpadding="2">
|
||||
<tr>
|
||||
<td style="width:25%;">25% column</td>
|
||||
<td style="width:75%;">75% column</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:25%;"><img src="images/tcpdf_logo.jpg" alt="TCPDF logo" style="width:100%;" /></td>
|
||||
<td style="width:75%;"><img src="images/tcpdf_logo.jpg" alt="TCPDF logo" style="width:50%;" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table style="width:160mm;" border="1" cellspacing="0" cellpadding="2">
|
||||
<tr>
|
||||
<td style="width:40mm;"><img src="images/tcpdf_logo.jpg" alt="TCPDF logo" style="width:100%;" /></td>
|
||||
<td>The image on the left fills the width of its 40mm cell (width:100%).</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr style="width:50%;" />
|
||||
<p>The horizontal rule above spans 50% of the container width.</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html6, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E044_toc_index.php
|
||||
*
|
||||
* @since 2017-05-08
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 044');
|
||||
$pdf->setTitle('Table of Contents and Index');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf toc index bookmarks pagination');
|
||||
$pdf->setPDFFilename('044_toc_index.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont1 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 12);
|
||||
|
||||
// The bold heading font is derived from the base font with cloneFont() instead of being inserted
|
||||
// explicitly: the bold definition file (dejavusansb.json) is resolved from the requested style,
|
||||
// so the headings below and the top-level entries of the generated TOC (that addTOC() renders by
|
||||
// cloning the current font with the 'B' style) are really bold and not just the regular glyphs.
|
||||
$bfont2 = $pdf->font->cloneFont($pdf->pon, null, 'B', 18);
|
||||
|
||||
$bfont3 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
// test images directory
|
||||
$imgdir = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/');
|
||||
|
||||
// ----------
|
||||
|
||||
$sections = [
|
||||
[
|
||||
'title' => 'Introduction',
|
||||
'summary' => 'This page introduces the outline entries that will be collected by addTOC into a generated table of contents.',
|
||||
'topic' => 'The top-level bookmark uses the same explicit style arguments shown in the overview example.',
|
||||
'color' => 'blue',
|
||||
],
|
||||
[
|
||||
'title' => 'Planning',
|
||||
'summary' => 'This page adds another destination so the table of contents can render a second page number.',
|
||||
'topic' => 'A second level bookmark is also added on each page to show indented TOC entries.',
|
||||
'color' => 'green',
|
||||
],
|
||||
[
|
||||
'title' => 'Execution',
|
||||
'summary' => 'This page stands in for the main body of the document and contributes more outline targets.',
|
||||
'topic' => 'Using separate pages makes the addTOC output easier to verify visually.',
|
||||
'color' => 'red',
|
||||
],
|
||||
[
|
||||
'title' => 'Results',
|
||||
'summary' => 'This last content page completes the sample before the dedicated TOC page is inserted.',
|
||||
'topic' => 'The final PDF contains five pages total: four content pages and one generated TOC page.',
|
||||
'color' => 'orange',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($sections as $index => $section) {
|
||||
$page = $pdf->addPage();
|
||||
$pdf->setBookmark(
|
||||
name: $section['title'],
|
||||
link: '',
|
||||
level: 0,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: $section['color'],
|
||||
);
|
||||
$pdf->setBookmark(
|
||||
name: $section['title'] . ' notes',
|
||||
link: '',
|
||||
level: 1,
|
||||
page: -1,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: '',
|
||||
color: 'black',
|
||||
);
|
||||
|
||||
$pdf->page->addContent($bfont2['out'], $page['pid']);
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell(
|
||||
txt: 'Example 044 - ' . $section['title'],
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
),
|
||||
$page['pid'],
|
||||
);
|
||||
|
||||
$pdf->page->addContent($bfont3['out'], $page['pid']);
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell(
|
||||
txt: 'Page ' . ($index + 1) . ' of 4',
|
||||
posx: 15,
|
||||
posy: 34,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
),
|
||||
$page['pid'],
|
||||
);
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell(
|
||||
txt: $section['summary'],
|
||||
posx: 15,
|
||||
posy: 48,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
),
|
||||
$page['pid'],
|
||||
);
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell(
|
||||
txt: $section['topic'],
|
||||
posx: 15,
|
||||
posy: 62,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
),
|
||||
$page['pid'],
|
||||
);
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
$pageTOC = $pdf->addPage();
|
||||
$pdf->setBookmark(name: 'TOC', link: '', level: 0, page: -1, posx: 0, posy: 0, fstyle: 'B', color: 'black');
|
||||
|
||||
$pdf->page->addContent($bfont2['out'], $pageTOC['pid']);
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell(
|
||||
txt: 'Table of contents',
|
||||
posx: 15,
|
||||
posy: 18,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
),
|
||||
$pageTOC['pid'],
|
||||
);
|
||||
$pdf->page->addContent($bfont1['out'], $pageTOC['pid']);
|
||||
|
||||
$pdf->setDefaultCellMargin(top: 0, right: 0, bottom: 0, left: 0);
|
||||
$pdf->setDefaultCellPadding(top: 1, right: 1, bottom: 1, left: 1);
|
||||
|
||||
$style_cell_toc = [
|
||||
'all' => [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'round',
|
||||
'lineJoin' => 'round',
|
||||
'miterLimit' => 0,
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$pdf->graph->add($style_cell_toc);
|
||||
|
||||
$pdf->addTOC(page: -1, posx: 15, posy: 30, width: 170, rtl: false);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// ----------
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// ----------
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E045_encryption_and_permissions.php
|
||||
*
|
||||
* @since 2026-04-27
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
$fileId = \md5('E045_encryption_and_permissions');
|
||||
$encrypt = new \Com\Tecnick\Pdf\Encrypt\Encrypt(
|
||||
enabled: true,
|
||||
file_id: $fileId,
|
||||
mode: 2,
|
||||
permissions: ['modify', 'copy', 'annot-forms', 'assemble'],
|
||||
user_pass: 'demo-user',
|
||||
owner_pass: 'demo-owner',
|
||||
);
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: $encrypt,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 045');
|
||||
$pdf->setTitle('Encryption and Permissions');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf encryption permissions user password owner password rights');
|
||||
$pdf->setPDFFilename('E045_encryption_and_permissions.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$page01 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$html = <<<HTML
|
||||
<h1>Encryption and Permissions</h1>
|
||||
<p>This document demonstrates PDF encryption and permission controls using tc-lib-pdf.
|
||||
The file is protected with a user password (<em>demo-user</em>) and an owner password (<em>demo-owner</em>).
|
||||
Encryption restricts unauthorized access while the owner password grants full control.
|
||||
The allowed permissions for this document are: <strong>modify</strong>, <strong>copy</strong>,
|
||||
<strong>annot-forms</strong>, and <strong>assemble</strong>.
|
||||
All other operations, such as printing, are denied.</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 20, posy: 10, width: 180);
|
||||
|
||||
// ----------
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E046_pangrams.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 046');
|
||||
$pdf->setTitle('Pangrams');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example pangrams unicode multilingual');
|
||||
$pdf->setPDFFilename('046_pangrams.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent(false);
|
||||
|
||||
// unifont covers the full Unicode BMP including Arabic, Hebrew, Thai,
|
||||
// Devanagari, Hangul, and CJK Unified Ideographs.
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'unifont', '', 14);
|
||||
|
||||
$page = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$html = '<h1>Pangrams</h1>';
|
||||
|
||||
// English
|
||||
$html .= '<h2>English</h2>';
|
||||
$html .= '<p>The quick brown fox jumps over the lazy dog.</p>';
|
||||
|
||||
// Arabic (RTL)
|
||||
$html .= '<h2>Arabic (العربية)</h2>';
|
||||
$html .=
|
||||
'<div style="text-align:right">' . 'صِف خَلقَ خَودِكِ كَمِثلِ الشَّمسِ إِذ بَزَغَت' . ' — يَحظى الضَّجيعُ بِها نَجلاءَ مِعطارِ' . '</div>';
|
||||
|
||||
// Hebrew (RTL)
|
||||
$html .= '<h2>Hebrew (עברית)</h2>';
|
||||
$html .= '<div style="text-align:right">' . 'דג סקרן שט בים מאוכזב ולפתע מצא חברה' . '</div>';
|
||||
|
||||
// Thai
|
||||
$html .= '<h2>Thai (ภาษาไทย)</h2>';
|
||||
$html .=
|
||||
'<p>'
|
||||
. 'เป็นมนุษย์สุดประเสริฐเลิศคุณค่า'
|
||||
. ' กว่าบรรดาฝูงสัตว์เดรัจฉาน'
|
||||
. ' จงฝ่าฟันพัฒนาวิชาการ'
|
||||
. ' อย่าล้างผลาญฤๅเข่นฆ่าบีฑาใคร'
|
||||
. '</p>';
|
||||
|
||||
// Devanagari (Hindi)
|
||||
$html .= '<h2>Devanagari (देवनागरी)</h2>';
|
||||
$html .= '<p>' . 'ऋषि सुयश ने प्रख्यात ग्रंथ की रचना करके हमें ज्ञान दिया।' . '</p>';
|
||||
|
||||
// Hangul (Korean)
|
||||
$html .= '<h2>Hangul (한글)</h2>';
|
||||
$html .= '<p>' . '키스의 고유조건은 입술끼리 만나야 하고' . ' 특별한 기술은 필요치 않다' . '</p>';
|
||||
|
||||
// Greek
|
||||
$html .= '<h2>Greek (Ελληνικά)</h2>';
|
||||
$html .= '<p>' . 'Ξεσκεπάζω την ψυχοφθόρα βδελυγμία.' . '</p>';
|
||||
|
||||
// Japanese
|
||||
$html .= '<h2>Japanese (日本語)</h2>';
|
||||
$html .=
|
||||
'<p>'
|
||||
. 'いろはにほへと ちりぬるを わかよたれそ つねならむ'
|
||||
. ' うゐのおくやま けふこえて あさきゆめみし ゑひもせす'
|
||||
. '</p>';
|
||||
|
||||
// Russian
|
||||
$html .= '<h2>Russian (Русский)</h2>';
|
||||
$html .= '<p>' . 'Съешь же ещё этих мягких французских булок, да выпей чаю.' . '</p>';
|
||||
|
||||
// Armenian
|
||||
$html .= '<h2>Armenian (Հայերեն)</h2>';
|
||||
$html .= '<p>' . 'Բոլոր մարդիկ ծնվում են ազատ և հավասար իրենց արժանապատվությամբ և իրավունքներով։' . '</p>';
|
||||
|
||||
// Georgian
|
||||
$html .= '<h2>Georgian (ქართული)</h2>';
|
||||
$html .= '<p>' . 'გთხოვთ ახლავე გაიაროთ რეგისტრაცია უფასო პროგრამაზე.' . '</p>';
|
||||
|
||||
// Tamil
|
||||
$html .= '<h2>Tamil (தமிழ்)</h2>';
|
||||
$html .= '<p>' . 'யாமறிந்த மொழிகளிலே தமிழ்மொழி போல் இனிதாவது எங்கும் காணோம்.' . '</p>';
|
||||
|
||||
// Bengali
|
||||
$html .= '<h2>Bengali (বাংলা)</h2>';
|
||||
$html .= '<p>' . 'সুপ্রিয় বন্ধুগণ, আমরা বাংলা ভাষায় কথা বলি।' . '</p>';
|
||||
|
||||
// Amharic
|
||||
$html .= '<h2>Amharic (አማርኛ)</h2>';
|
||||
$html .= '<p>' . 'ሰው ናቸው ወይስ ሃሳቤን ሳልጨርስ ትዕዛዙን ሰጡ?' . '</p>';
|
||||
|
||||
// Khmer
|
||||
$html .= '<h2>Khmer (ភាសាខ្មែរ)</h2>';
|
||||
$html .= '<p>' . 'ខ្ញុំអាចញ៉ាំកញ្ចក់បានដោយគ្មានបញ្ហា។' . '</p>';
|
||||
|
||||
// Tibetan
|
||||
$html .= '<h2>Tibetan (བོད་སྐད།)</h2>';
|
||||
$html .= '<p>' . 'ང་གཤེགས་ཀྱི་ཡིག་གུ་ཟ་ཐུབ་ཀྱི་ཡོད། དེས་ང་ལ་གནོད་པ་མི་བྱེད།' . '</p>';
|
||||
|
||||
// Chinese (Traditional — Thousand Character Classic)
|
||||
$html .= '<h2>Chinese (中文)</h2>';
|
||||
$html .= '<p>' . '天地玄黄,宇宙洪荒。日月盈昃,辰宿列张。' . '寒来暑往,秋收冬藏。闰余成岁,律吕调阳。' . '</p>';
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 10, posy: 10, width: 190);
|
||||
|
||||
// =============================================================
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E047_remote_resources_security.php
|
||||
*
|
||||
* Demonstrates fileOptions host allowlisting and remote fetch controls while
|
||||
* keeping the default run deterministic (no network dependency required).
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$imgdir = (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images');
|
||||
$allowedPaths = array_values(array_unique(array_filter([
|
||||
K_PATH_FONTS,
|
||||
$imgdir,
|
||||
])));
|
||||
|
||||
$curlopts = [];
|
||||
$fixedCurlOpts = [];
|
||||
|
||||
if (defined('CURLOPT_CONNECTTIMEOUT')) {
|
||||
$curlopts[CURLOPT_CONNECTTIMEOUT] = 4;
|
||||
}
|
||||
|
||||
if (defined('CURLOPT_TIMEOUT')) {
|
||||
$curlopts[CURLOPT_TIMEOUT] = 8;
|
||||
}
|
||||
|
||||
if (defined('CURLOPT_SSL_VERIFYHOST')) {
|
||||
$fixedCurlOpts[CURLOPT_SSL_VERIFYHOST] = 2;
|
||||
}
|
||||
|
||||
if (defined('CURLOPT_SSL_VERIFYPEER')) {
|
||||
$fixedCurlOpts[CURLOPT_SSL_VERIFYPEER] = true;
|
||||
}
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
fileOptions: [
|
||||
'allowedHosts' => ['assets.example.com'],
|
||||
'allowedPaths' => $allowedPaths,
|
||||
'maxRemoteSize' => 1024 * 1024,
|
||||
'curlopts' => $curlopts,
|
||||
'fixedCurlOpts' => $fixedCurlOpts,
|
||||
],
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 047');
|
||||
$pdf->setTitle('Remote Resource Security');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example remote resources fileOptions security');
|
||||
$pdf->setPDFFilename('047_remote_resources_security.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$titlefont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
$textfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$smallfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 8);
|
||||
|
||||
$page = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
$pdf->page->addContent($titlefont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Remote Resources and fileOptions Security',
|
||||
posx: 15,
|
||||
posy: 14,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($textfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: "This example configures host allowlisting, local path allowlisting, and transfer limits.\n"
|
||||
. "It renders local assets by default for deterministic runs.\n"
|
||||
. 'Optional remote probe can be enabled with ?probe=1 in browser mode.',
|
||||
posx: 15,
|
||||
posy: 26,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1.3,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$localImage = $imgdir . '/200x100_RGB.png';
|
||||
$statusY = 60.0;
|
||||
|
||||
try {
|
||||
$iid = $pdf->image->add($localImage);
|
||||
$pdf->page->addContent($pdf->image->getSetImage($iid, 15, 54, 70, 35, (float) $page['height']));
|
||||
$localStatus = 'Local image load: OK (' . basename($localImage) . ')';
|
||||
} catch (\Throwable $e) {
|
||||
$localStatus = 'Local image load: FAILED - ' . $e->getMessage();
|
||||
}
|
||||
|
||||
$pdf->page->addContent($smallfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $localStatus,
|
||||
posx: 90,
|
||||
posy: $statusY,
|
||||
width: 105,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$probe = false;
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
$probe = isset($_GET['probe']) && $_GET['probe'] === '1';
|
||||
}
|
||||
|
||||
$remoteStatus = 'Remote probe: skipped (add ?probe=1 to run a blocked-host fetch attempt).';
|
||||
if ($probe) {
|
||||
try {
|
||||
$pdf->image->add('https://untrusted.example.invalid/logo.png');
|
||||
$remoteStatus = 'Remote probe: request did not raise an exception (check your environment wrappers).';
|
||||
} catch (\Throwable $e) {
|
||||
$remoteStatus = 'Remote probe: blocked/failure as expected - ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $remoteStatus,
|
||||
posx: 15,
|
||||
posy: 96,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1.2,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($textfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: "Configured policy:\n"
|
||||
. "- allowedHosts: assets.example.com\n"
|
||||
. "- allowedPaths: fonts + image fixture directories\n"
|
||||
. "- maxRemoteSize: 1 MiB\n"
|
||||
. "- curlopts: short connect/transfer timeout\n"
|
||||
. '- fixedCurlOpts: TLS peer+host verification',
|
||||
posx: 15,
|
||||
posy: 112,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1.35,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E048_page_boxes_prepress.php
|
||||
*
|
||||
* Demonstrates Media/Crop/Bleed/Trim/Art page boxes for print-oriented
|
||||
* workflows, plus visible guides for quick prepress validation.
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 048');
|
||||
$pdf->setTitle('Page Boxes and Prepress Guides');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example page boxes MediaBox CropBox BleedBox TrimBox ArtBox');
|
||||
$pdf->setPDFFilename('048_page_boxes_prepress.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$probe = false;
|
||||
if (PHP_SAPI === 'cli') {
|
||||
$probe = (string) getenv('TC_EXAMPLE_PROBE') === '1';
|
||||
} else {
|
||||
$probe = isset($_GET['probe']) && $_GET['probe'] === '1';
|
||||
}
|
||||
|
||||
$titlefont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 13);
|
||||
$textfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 9);
|
||||
|
||||
$pageBoxesMm = [
|
||||
'CropBox' => ['llx' => 5.0, 'lly' => 5.0, 'urx' => 205.0, 'ury' => 292.0],
|
||||
'BleedBox' => ['llx' => 3.0, 'lly' => 3.0, 'urx' => 207.0, 'ury' => 294.0],
|
||||
'TrimBox' => ['llx' => 10.0, 'lly' => 10.0, 'urx' => 200.0, 'ury' => 287.0],
|
||||
'ArtBox' => ['llx' => 20.0, 'lly' => 20.0, 'urx' => 190.0, 'ury' => 277.0],
|
||||
];
|
||||
|
||||
$pageBoxesPt = [];
|
||||
foreach ($pageBoxesMm as $name => $coords) {
|
||||
$pageBoxesPt[$name] = [
|
||||
'llx' => $pdf->toPoints((float) $coords['llx']),
|
||||
'lly' => $pdf->toPoints((float) $coords['lly']),
|
||||
'urx' => $pdf->toPoints((float) $coords['urx']),
|
||||
'ury' => $pdf->toPoints((float) $coords['ury']),
|
||||
];
|
||||
}
|
||||
|
||||
$page = $pdf->addPage([
|
||||
'format' => 'A4',
|
||||
'box' => $pageBoxesPt,
|
||||
]);
|
||||
|
||||
$pdf->page->addContent($titlefont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Page Boxes: Media/Crop/Bleed/Trim/Art',
|
||||
posx: 25,
|
||||
posy: 14,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($textfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: "This sheet overlays the configured page boxes to verify prepress bounds.\n"
|
||||
. 'Coordinates are defined in page-box metadata and rendered here as guides.',
|
||||
posx: 25,
|
||||
posy: 24,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1.2,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$styles = [
|
||||
'MediaBox' => ['all' => ['lineWidth' => 0.3, 'lineColor' => '#000000', 'dashArray' => []]],
|
||||
'CropBox' => ['all' => ['lineWidth' => 0.3, 'lineColor' => '#1f77b4', 'dashArray' => [2, 1]]],
|
||||
'BleedBox' => ['all' => ['lineWidth' => 0.3, 'lineColor' => '#d62728', 'dashArray' => [1, 1]]],
|
||||
'TrimBox' => ['all' => ['lineWidth' => 0.35, 'lineColor' => '#2ca02c', 'dashArray' => []]],
|
||||
'ArtBox' => ['all' => ['lineWidth' => 0.3, 'lineColor' => '#9467bd', 'dashArray' => [3, 1]]],
|
||||
];
|
||||
|
||||
$boxes =
|
||||
[
|
||||
'MediaBox' => [
|
||||
'llx' => 0.0,
|
||||
'lly' => 0.0,
|
||||
'urx' => (float) $page['width'],
|
||||
'ury' => (float) $page['height'],
|
||||
],
|
||||
] + $pageBoxesMm;
|
||||
$pageHeight = (float) $page['height'];
|
||||
|
||||
$labelY = 46.0;
|
||||
foreach (['MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'] as $name) {
|
||||
if (!isset($boxes[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$box = $boxes[$name];
|
||||
$x = (float) ($box['llx'] ?? 0.0);
|
||||
$y = $pageHeight - (float) ($box['ury'] ?? 0.0);
|
||||
$w = (float) ($box['urx'] ?? 0.0) - (float) ($box['llx'] ?? 0.0);
|
||||
$h = (float) ($box['ury'] ?? 0.0) - (float) ($box['lly'] ?? 0.0);
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getRect($x, $y, $w, $h, 'D', $styles[$name]));
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $name
|
||||
. sprintf(
|
||||
' [%.1f, %.1f, %.1f, %.1f]',
|
||||
(float) ($box['llx'] ?? 0.0),
|
||||
(float) ($box['lly'] ?? 0.0),
|
||||
(float) ($box['urx'] ?? 0.0),
|
||||
(float) ($box['ury'] ?? 0.0),
|
||||
),
|
||||
posx: 25,
|
||||
posy: $labelY,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$labelY += 5.0;
|
||||
}
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: "Tip: use TrimBox as the final cut size and keep critical artwork inside ArtBox.\n"
|
||||
. 'BleedBox extends beyond trim to avoid white edges after cutting.',
|
||||
posx: 25,
|
||||
posy: 72,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1.2,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
if ($probe) {
|
||||
$matches = [];
|
||||
$probeRows = [];
|
||||
$pointsPerUnit = $pdf->toPoints(1.0);
|
||||
$pattern = '/\\/(MediaBox|CropBox|BleedBox|TrimBox|ArtBox)\\s*\\[\\s*([0-9.+-]+)\\s+([0-9.+-]+)\\s+([0-9.+-]+)\\s+([0-9.+-]+)\\s*\\]/';
|
||||
if (\preg_match_all($pattern, $rawpdf, $matches, PREG_SET_ORDER) === false) {
|
||||
$probeRows[] = 'Page-box probe: unable to parse page-box dictionaries.';
|
||||
} else {
|
||||
foreach ($matches as $vals) {
|
||||
$name = (string) $vals[1];
|
||||
$llx = (float) $vals[2];
|
||||
$lly = (float) $vals[3];
|
||||
$urx = (float) $vals[4];
|
||||
$ury = (float) $vals[5];
|
||||
$wPt = $urx - $llx;
|
||||
$hPt = $ury - $lly;
|
||||
$probeRows[] = sprintf(
|
||||
'%s PDF=[%.3f %.3f %.3f %.3f] sizePt=%.3fx%.3f sizeUnit=%.3fx%.3f',
|
||||
$name,
|
||||
$llx,
|
||||
$lly,
|
||||
$urx,
|
||||
$ury,
|
||||
$wPt,
|
||||
$hPt,
|
||||
$pointsPerUnit > 0 ? $wPt / $pointsPerUnit : 0.0,
|
||||
$pointsPerUnit > 0 ? $hPt / $pointsPerUnit : 0.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$output = "\n[E048 page-box probe]\n" . implode("\n", $probeRows) . "\n";
|
||||
if (PHP_SAPI === 'cli') {
|
||||
fwrite(STDERR, $output);
|
||||
} else {
|
||||
error_log($output);
|
||||
}
|
||||
}
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E049_output_targets_integration.php
|
||||
*
|
||||
* Demonstrates routing one generated PDF to multiple output targets:
|
||||
* render, download, save, and MIME attachment payload.
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 049');
|
||||
$pdf->setTitle('Output Targets Integration');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example output render download save mime');
|
||||
$pdf->setPDFFilename('049_output_targets_integration.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$titlefont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
$textfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
|
||||
$mode = 'render';
|
||||
if (PHP_SAPI === 'cli') {
|
||||
$mode = (string) ($argv[1] ?? 'render');
|
||||
} elseif (isset($_GET['mode']) && is_string($_GET['mode'])) {
|
||||
$mode = $_GET['mode'];
|
||||
}
|
||||
|
||||
$mode = strtolower(trim($mode));
|
||||
$allowedModes = ['render', 'download', 'save', 'mime'];
|
||||
if (!in_array($mode, $allowedModes, true)) {
|
||||
$mode = 'render';
|
||||
}
|
||||
|
||||
$pdf->page->addContent($titlefont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Output Targets Integration',
|
||||
posx: 15,
|
||||
posy: 16,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($textfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: "This example creates one raw PDF payload and sends it through different targets.\n"
|
||||
. 'Current mode: '
|
||||
. strtoupper($mode)
|
||||
. "\n"
|
||||
. "Browser usage: ?mode=render|download|save|mime\n"
|
||||
. 'CLI usage: php examples/E049_output_targets_integration.php render',
|
||||
posx: 15,
|
||||
posy: 30,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1.35,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
if ($mode === 'download') {
|
||||
$pdf->downloadPDF(rawpdf: $rawpdf);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($mode === 'save') {
|
||||
$targetDir = (string) realpath(__DIR__ . '/../target');
|
||||
$pdf->savePDF(path: $targetDir, rawpdf: $rawpdf);
|
||||
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
}
|
||||
|
||||
echo 'Saved PDF to: ' . $targetDir . '/' . '049_output_targets_integration.pdf' . "\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($mode === 'mime') {
|
||||
$mimeAttachment = $pdf->getMIMEAttachmentPDF(rawpdf: $rawpdf);
|
||||
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
}
|
||||
|
||||
echo "MIME attachment preview (first 20 lines):\n\n";
|
||||
$lines = explode("\n", str_replace("\r\n", "\n", $mimeAttachment));
|
||||
echo implode("\n", array_slice($lines, 0, 20));
|
||||
echo "\n\nTotal MIME length: " . strlen($mimeAttachment) . " bytes\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E050_shipping_label_barcodes.php
|
||||
*
|
||||
* Demonstrates a production-style shipping label with 1D and 2D barcodes,
|
||||
* quiet-zone padding, and human-readable tracking details.
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 050');
|
||||
$pdf->setTitle('Shipping Label with Barcodes');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example shipping label barcode qrcode code128');
|
||||
$pdf->setPDFFilename('050_shipping_label_barcodes.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// Initialize default font for text rendering
|
||||
$defaultFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 8);
|
||||
|
||||
$pdf->addPage([
|
||||
'width' => 100.0,
|
||||
'height' => 150.0,
|
||||
'margin' => [
|
||||
'PL' => 5.0,
|
||||
'PR' => 5.0,
|
||||
'CT' => 5.0,
|
||||
'CB' => 5.0,
|
||||
],
|
||||
]);
|
||||
|
||||
$frameStyle = ['all' => ['lineWidth' => 0.35, 'lineColor' => '#111111']];
|
||||
$sepStyle = ['all' => ['lineWidth' => 0.2, 'lineColor' => '#555555', 'dashArray' => [2, 1]]];
|
||||
$barcodeStyle = [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'black',
|
||||
'fillColor' => 'black',
|
||||
];
|
||||
|
||||
// Draw frame and separators
|
||||
$pdf->page->addContent($pdf->graph->getRect(4, 4, 92, 142, 'D', $frameStyle));
|
||||
$pdf->page->addContent($pdf->graph->getLine(4, 35, 96, 35, $sepStyle['all']));
|
||||
$pdf->page->addContent($pdf->graph->getLine(4, 94, 96, 94, $sepStyle['all']));
|
||||
|
||||
// Header section
|
||||
$headerHtml = '<div style="text-align: left;">
|
||||
<p style="font-family: helvetica; font-weight: bold; font-size: 11pt; margin: 0;">EXPRESS SHIPPING</p>
|
||||
<p style="font-family: helvetica; font-weight: bold; font-size: 11pt; margin: 0;">PRIORITY</p>
|
||||
</div>';
|
||||
$pdf->addHTMLCell(html: $headerHtml, posx: 8, posy: 9, width: 50);
|
||||
|
||||
// QR code in top-right
|
||||
$qrPayload = "TRACK:1Z999AA10123456784\nORDER:SO-2026-05-0018\nSERVICE:EXPRESS-24\nFROM:NL-RTM-W17\nTO:DE-HAM-ACME";
|
||||
$pdf->page->addContent($pdf->getBarcode(
|
||||
type: 'QRCODE,M',
|
||||
code: $qrPayload,
|
||||
posx: 72,
|
||||
posy: 9,
|
||||
width: 20,
|
||||
height: 20,
|
||||
padding: [1, 1, 1, 1],
|
||||
style: $barcodeStyle,
|
||||
));
|
||||
|
||||
// Address section
|
||||
$addressHtml = '<table cellpadding="1" cellspacing="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td width="50%" style="vertical-align: top; font-family: helvetica; font-size: 8pt;">
|
||||
<p style="font-weight: bold; margin: 0; padding-bottom: 1mm;"><u>SHIP FROM</u></p>
|
||||
<p style="margin: 0; line-height: 1.3;">Warehouse 17<br/>42 Logistics Rd<br/>Rotterdam, NL</p>
|
||||
</td>
|
||||
<td width="50%" style="vertical-align: top; font-family: helvetica; font-size: 8pt;">
|
||||
<p style="font-weight: bold; margin: 0; padding-bottom: 1mm;"><u>SHIP TO</u></p>
|
||||
<p style="margin: 0; line-height: 1.3;">Acme Retail<br/>18 Harbor Street<br/>Hamburg, DE</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="font-family: helvetica; font-size: 8pt; margin: 1mm 0 0 0; text-align: center;">
|
||||
<em>Scan for full shipment payload</em>
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $addressHtml, posx: 8, posy: 37, width: 84);
|
||||
|
||||
$tracking = '1Z999AA10123456784';
|
||||
$orderRef = 'SO-2026-05-0018';
|
||||
$service = 'EXPRESS-24';
|
||||
|
||||
// Tracking section
|
||||
$trackingHtml =
|
||||
'<div style="font-family: courier; font-weight: bold; font-size: 11pt; margin-bottom: 2mm;">
|
||||
'
|
||||
. htmlspecialchars($tracking)
|
||||
. '
|
||||
</div>
|
||||
<ul style="font-family: helvetica; font-size: 8pt;">
|
||||
<li>Order: '
|
||||
. htmlspecialchars($orderRef)
|
||||
. '</li>
|
||||
<li>Service: '
|
||||
. htmlspecialchars($service)
|
||||
. '</li>
|
||||
</ul>';
|
||||
$pdf->addHTMLCell(html: $trackingHtml, posx: 8, posy: 96, width: 84);
|
||||
|
||||
// 1D barcode
|
||||
$pdf->page->addContent($pdf->getBarcode(
|
||||
type: 'C128',
|
||||
code: $tracking,
|
||||
posx: 8,
|
||||
posy: 115,
|
||||
width: 80,
|
||||
height: 14,
|
||||
padding: [1, 1, 1, 1],
|
||||
style: $barcodeStyle,
|
||||
));
|
||||
|
||||
// Footer text
|
||||
$footerHtml = '<p style="font-family: helvetica; font-size: 8pt; margin: 0; text-align: left; line-height: 1.2;">
|
||||
Quiet zones are intentionally reserved around both symbols to improve scanner reliability.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $footerHtml, posx: 8, posy: 136, width: 84);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E051_viewer_preferences_navigation.php
|
||||
*
|
||||
* Demonstrates viewer preference configuration, display mode selection,
|
||||
* bookmarks, named destinations, and internal link annotations.
|
||||
*
|
||||
* What this demonstrates:
|
||||
* - setDisplayMode(): initial zoom, page layout, and page mode.
|
||||
* - setViewerPreferences(): HideToolbar, CenterWindow, Duplex, PrintScaling, etc.
|
||||
* - setNamedDestination(): register named jump targets for cross-document linking.
|
||||
* - addInternalLink(): page/position link ID for use inside the same document.
|
||||
* - setLink() + page->addAnnotRef(): clickable rectangle annotations.
|
||||
* - setBookmark(): outline entries that drive the bookmark panel.
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 051');
|
||||
$pdf->setTitle('Viewer Preferences & Navigation');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf viewer preferences navigation bookmarks named destinations links');
|
||||
$pdf->setPDFFilename('051_viewer_preferences_navigation.pdf');
|
||||
|
||||
// ----------
|
||||
// Viewer preferences
|
||||
// The viewer will open the document in single-page layout with outline panel
|
||||
// visible. The window is centered on screen and the document title shown in
|
||||
// the title bar.
|
||||
|
||||
$pdf->setViewerPreferences([
|
||||
'DisplayDocTitle' => true,
|
||||
'CenterWindow' => true,
|
||||
'FitWindow' => false,
|
||||
'HideToolbar' => false,
|
||||
'HideMenubar' => false,
|
||||
'Duplex' => 'DuplexFlipLongEdge',
|
||||
'PrintScaling' => 'none',
|
||||
'NumCopies' => 1,
|
||||
'PrintPageRange' => [1, 4],
|
||||
'NonFullScreenPageMode' => 'UseOutlines',
|
||||
]);
|
||||
|
||||
// Display mode: open at full width, single-page layout, with outlines panel.
|
||||
$pdf->setDisplayMode(
|
||||
zoom: \Com\Tecnick\Pdf\DisplayZoom::FullWidth,
|
||||
layout: \Com\Tecnick\Pdf\Page\PageLayout::SinglePage,
|
||||
mode: \Com\Tecnick\Pdf\Page\PageDisplayMode::UseOutlines,
|
||||
);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
|
||||
$headFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 16);
|
||||
$subFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 11);
|
||||
$bodyFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
// ===| Page 1 – Cover |======================================================
|
||||
|
||||
$page1 = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
// Register a named destination at the top of page 1. External documents or
|
||||
// bookmark links can jump here via '#cover'.
|
||||
$pdf->setNamedDestination(name: 'cover', page: $page1['pid'], posx: 0, posy: 0);
|
||||
|
||||
$pdf->setBookmark(
|
||||
name: 'Cover',
|
||||
link: '#cover',
|
||||
level: 0,
|
||||
page: $page1['pid'],
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: 'darkblue',
|
||||
);
|
||||
|
||||
$coverHtml = '<h1 style="font-family: helvetica; color: #1a3c6e; text-align: center; margin-top: 30mm;">
|
||||
Viewer Preferences & Navigation Demo
|
||||
</h1>
|
||||
<p style="font-family: helvetica; font-size: 11pt; text-align: center; color: #444444;">
|
||||
tc-lib-pdf · Example 051
|
||||
</p>
|
||||
<hr/>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
This document demonstrates:
|
||||
</p>
|
||||
<ul style="font-family: helvetica; font-size: 10pt;">
|
||||
<li><strong>Viewer preferences</strong> — initial layout, duplex, print scaling, and window behavior.</li>
|
||||
<li><strong>Display mode</strong> — zoom, page layout, and panel visibility on open.</li>
|
||||
<li><strong>Named destinations</strong> — stable jump targets for cross-document links.</li>
|
||||
<li><strong>Internal link annotations</strong> — clickable regions mapped to page positions.</li>
|
||||
<li><strong>Bookmarks / outlines</strong> — hierarchical navigation panel entries.</li>
|
||||
</ul>
|
||||
<p style="font-family: helvetica; font-size: 10pt; margin-top: 8mm;">
|
||||
The navigation buttons on page 4 use <code>setLink</code> and <code>addInternalLink</code>
|
||||
to create clickable rectangles that jump to each chapter page.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $coverHtml, posx: 15, posy: 20, width: 170);
|
||||
|
||||
// ===| Page 2 – Chapter 1 |==================================================
|
||||
|
||||
$page2 = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
$destChapter1 = $pdf->setNamedDestination(name: 'chapter-1', page: $page2['pid'], posx: 0, posy: 0);
|
||||
$pdf->setBookmark(
|
||||
name: 'Chapter 1 — Overview',
|
||||
link: $destChapter1,
|
||||
level: 0,
|
||||
page: $page2['pid'],
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: 'darkgreen',
|
||||
);
|
||||
$pdf->setBookmark(name: '1.1 Introduction', link: '', level: 1, page: $page2['pid'], posx: 0, posy: 25);
|
||||
|
||||
$ch1Html = '<h2 style="font-family: helvetica; color: #1a6e3c;">Chapter 1 — Overview</h2>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
This chapter is the target of the named destination <code>chapter-1</code>.
|
||||
Clicking the button on the navigation page jumps here via an internal link annotation.
|
||||
</p>
|
||||
<h3 style="font-family: helvetica; color: #1a6e3c;">1.1 Introduction</h3>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
The <code>setNamedDestination()</code> method registers a jump target that can be referenced
|
||||
from bookmarks (using the <code>#</code> prefix), from link annotations, or from external
|
||||
documents pointing to this file.
|
||||
</p>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
Named destinations are stored in the PDF <em>/Dests</em> dictionary and are independent
|
||||
of page numbering — they remain stable even if pages are reordered.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $ch1Html, posx: 15, posy: 20, width: 170);
|
||||
|
||||
// ===| Page 3 – Chapter 2 |==================================================
|
||||
|
||||
$page3 = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
$destChapter2 = $pdf->setNamedDestination(name: 'chapter-2', page: $page3['pid'], posx: 0, posy: 0);
|
||||
$pdf->setBookmark(
|
||||
name: 'Chapter 2 — Viewer Preferences',
|
||||
link: $destChapter2,
|
||||
level: 0,
|
||||
page: $page3['pid'],
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: 'darkred',
|
||||
);
|
||||
$pdf->setBookmark(name: '2.1 Preference Keys', link: '', level: 1, page: $page3['pid'], posx: 0, posy: 25);
|
||||
|
||||
$prefTable = '<h2 style="font-family: helvetica; color: #6e1a1a;">Chapter 2 — Viewer Preferences</h2>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
The <code>setViewerPreferences()</code> method populates the <em>/ViewerPreferences</em>
|
||||
dictionary in the PDF catalog. The following preferences are active in this document:
|
||||
</p>
|
||||
<table border="1" cellpadding="2" cellspacing="0" style="font-family: helvetica; font-size: 9pt; width: 100%;">
|
||||
<tr style="background-color: #dddddd;">
|
||||
<th>Key</th><th>Value</th><th>Effect</th>
|
||||
</tr>
|
||||
<tr><td>DisplayDocTitle</td><td>true</td><td>Show PDF title in window title bar.</td></tr>
|
||||
<tr><td>CenterWindow</td><td>true</td><td>Center the viewer window on screen.</td></tr>
|
||||
<tr><td>Duplex</td><td>DuplexFlipLongEdge</td><td>Default duplex setting for print dialog.</td></tr>
|
||||
<tr><td>PrintScaling</td><td>none</td><td>Disable auto-scaling in print dialog.</td></tr>
|
||||
<tr><td>NumCopies</td><td>1</td><td>Default copy count in print dialog.</td></tr>
|
||||
<tr><td>PrintPageRange</td><td>1–4</td><td>Default page range in print dialog.</td></tr>
|
||||
<tr><td>NonFullScreenPageMode</td><td>UseOutlines</td><td>Show outline panel when exiting full screen.</td></tr>
|
||||
</table>';
|
||||
$pdf->addHTMLCell(html: $prefTable, posx: 15, posy: 20, width: 170);
|
||||
|
||||
// ===| Page 4 – Navigation Map |=============================================
|
||||
|
||||
$page4 = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
$pdf->setBookmark(
|
||||
name: 'Navigation Map',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: $page4['pid'],
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: '',
|
||||
color: 'gray',
|
||||
);
|
||||
|
||||
$navHtml = '<h2 style="font-family: helvetica; color: #333333;">Navigation Map</h2>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
Each button below is a clickable link annotation (<code>setLink</code> + <code>addAnnotRef</code>)
|
||||
that uses <code>addInternalLink()</code> to jump to the start of a specific page.
|
||||
</p>
|
||||
<p style="font-family: helvetica; font-size: 10pt; margin-bottom: 8mm;">
|
||||
Alternatively, the bookmark panel (outline) on the left provides the same navigation
|
||||
via the bookmarks registered with <code>setBookmark()</code>.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $navHtml, posx: 15, posy: 20, width: 170);
|
||||
|
||||
// Define style for button boxes
|
||||
$btnFill = ['all' => ['lineWidth' => 0.3, 'lineColor' => '#333366', 'fillColor' => '#e8eef8']];
|
||||
$btnFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 11);
|
||||
$pdf->page->addContent($btnFont['out']);
|
||||
|
||||
// Helper to draw a navigation button and attach a link annotation
|
||||
$drawNavButton = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
float $bx,
|
||||
float $by,
|
||||
float $bw,
|
||||
float $bh,
|
||||
string $label,
|
||||
int $targetPage,
|
||||
array $btnFill,
|
||||
) use ($page4): void {
|
||||
$pdf->page->addContent($pdf->graph->getRect($bx, $by, $bw, $bh, 'DF', $btnFill));
|
||||
// Reset fill color to dark text after the rect draw, which left the fill color
|
||||
// set to the button background color, making the label text invisible.
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('#333366'));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $label,
|
||||
posx: $bx,
|
||||
posy: $by + 3,
|
||||
width: $bw,
|
||||
height: $bh - 3,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
$lnkid = $pdf->addInternalLink($targetPage, 0);
|
||||
$annid = $pdf->setLink(posx: $bx, posy: $by, width: $bw, height: $bh, link: $lnkid);
|
||||
$pdf->page->addAnnotRef($annid);
|
||||
};
|
||||
|
||||
$drawNavButton($pdf, 25, 80, 70, 14, 'Go to Cover (page 1)', $page1['pid'], $btnFill);
|
||||
$drawNavButton($pdf, 25, 100, 70, 14, 'Go to Chapter 1 (page 2)', $page2['pid'], $btnFill);
|
||||
$drawNavButton($pdf, 25, 120, 70, 14, 'Go to Chapter 2 (page 3)', $page3['pid'], $btnFill);
|
||||
|
||||
// Restore the plain body font in the internal font stack before addHTMLCell;
|
||||
// font->insert with 'B' above left the stack on the bold variant and would
|
||||
// cause addHTMLCell to capture/restore 'helveticabB' → undefined key warning.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
// Show named destination links using '#name' notation in bookmarks
|
||||
$namedNoteHtml = '<p style="font-family: helvetica; font-size: 9pt; color: #555555; margin-top: 10mm;">
|
||||
The bookmark entries above the buttons use <code>setNamedDestination()</code> targets
|
||||
(<code>#cover</code>, <code>#chapter-1</code>, <code>#chapter-2</code>).
|
||||
Named destinations survive page renumbering and can be referenced from external documents.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $namedNoteHtml, posx: 15, posy: 145, width: 170);
|
||||
|
||||
// ----------
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E052_custom_fonts_fallback.php
|
||||
*
|
||||
* Demonstrates custom font selection, Unicode coverage strategy, and
|
||||
* font-family fallback across multiple scripts.
|
||||
*
|
||||
* What this demonstrates:
|
||||
* - font->insert(): loading built-in and extended font families.
|
||||
* - Subset vs full-embed tradeoff (constructor $subsetfont flag).
|
||||
* - Choosing fonts by Unicode coverage: helvetica (Latin), dejavusans
|
||||
* (Latin + Greek + Cyrillic + IPA), unifont (full Unicode BMP).
|
||||
* - HTML font-family CSS mapping to pre-loaded font slots.
|
||||
* - Per-script font selection in addHTMLCell markup.
|
||||
*
|
||||
* Companion libraries: tc-lib-pdf-font, tc-lib-unicode, tc-lib-unicode-data.
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// K_PATH_FONTS must point to the directory holding .z and .php font metric files.
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// Subset font embedding: when $subsetfont = true (constructor arg 3), only the
|
||||
// glyphs actually used in the document are embedded. This produces smaller PDFs
|
||||
// but makes the font unsuitable for later editing. Set to false for archival PDFs
|
||||
// (PDF/A, PDF/UA) or whenever the full character set must be available.
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 052');
|
||||
$pdf->setTitle('Custom Fonts & Unicode Fallback');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf font unicode multilingual fallback subset dejavusans unifont');
|
||||
$pdf->setPDFFilename('052_custom_fonts_fallback.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Pre-load all font families that will be used in the document.
|
||||
// font->insert() returns a font descriptor array. The 'out' key contains
|
||||
// the PDF operator stream that must be injected onto a page before the
|
||||
// font is used. Loading fonts before addPage() registers them in the
|
||||
// font object pool; injecting 'out' at the start of each page activates
|
||||
// the font for that page.
|
||||
|
||||
// Helvetica: core Type-1, no embedding required, Latin + standard symbols only.
|
||||
$fHelvetica = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
$fHelveticaB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 11);
|
||||
|
||||
// Times New Roman (core): serif alternative for body text, Latin only.
|
||||
$fTimes = $pdf->font->insert($pdf->pon, 'times', '', 11);
|
||||
|
||||
// Courier (core): monospaced, Latin only; good for code samples.
|
||||
$fCourier = $pdf->font->insert($pdf->pon, 'courier', '', 10);
|
||||
|
||||
// DejaVu Sans: TrueType, Latin + Greek + Cyrillic + IPA + many other scripts.
|
||||
// Covers most Western European, Eastern European, and Slavic languages.
|
||||
$fDejavu = $pdf->font->insert($pdf->pon, 'dejavusans', '', 11);
|
||||
|
||||
// Unifont: TrueType, very broad Unicode BMP (plane 0) coverage including Arabic,
|
||||
// Hebrew, Thai, Devanagari, and many additional scripts.
|
||||
// File size is large; use subset=true when embedding it in production PDFs.
|
||||
$fUnifont = $pdf->font->insert($pdf->pon, 'unifont', '', 11);
|
||||
|
||||
// ===| Page 1 – Font Coverage Overview |=====================================
|
||||
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
$pdf->page->addContent($fHelvetica['out']);
|
||||
|
||||
$overviewHtml = '<h1 style="font-family: helvetica;">Font Selection & Unicode Fallback</h1>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
PDF viewers cannot substitute fonts automatically — every glyph must come from
|
||||
an embedded font resource. The strategy is:
|
||||
</p>
|
||||
<ol style="font-family: helvetica; font-size: 10pt;">
|
||||
<li>Use <strong>core Type-1 fonts</strong> (helvetica, times, courier) for Latin-only text to
|
||||
avoid embedding overhead.</li>
|
||||
<li>Upgrade to <strong>DejaVu Sans</strong> for pages that mix Latin with Greek, Cyrillic, or
|
||||
extended Latin (diacritics, IPA).</li>
|
||||
<li>Use <strong>Unifont</strong> for pages that require full Unicode BMP coverage (Arabic, Hebrew,
|
||||
Thai, Devanagari, Hangul, CJK).</li>
|
||||
</ol>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
In HTML cells, specify the font via <code>style="font-family: dejavusans"</code> or
|
||||
<code>style="font-family: unifont"</code>.
|
||||
The name must match the lowercase font identifier known to tc-lib-pdf-font.
|
||||
</p>
|
||||
<hr/>
|
||||
<h2 style="font-family: helvetica;">Core Type-1 Fonts (Latin)</h2>
|
||||
<p style="font-family: helvetica; font-size: 11pt;">
|
||||
<span style="font-family: helvetica;">Helvetica — The quick brown fox jumps over the lazy dog.</span>
|
||||
</p>
|
||||
<p style="font-family: times; font-size: 11pt;">
|
||||
<span style="font-family: times;">Times — The quick brown fox jumps over the lazy dog.</span>
|
||||
</p>
|
||||
<p style="font-family: courier; font-size: 10pt;">
|
||||
<span style="font-family: courier;">Courier — The quick brown fox jumps over the lazy dog.</span>
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $overviewHtml, posx: 15, posy: 20, width: 175);
|
||||
|
||||
// ===| Page 2 – DejaVu Sans: Latin + Greek + Cyrillic |======================
|
||||
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
$pdf->page->addContent($fDejavu['out']);
|
||||
|
||||
$dejavuHtml = '<h2 style="font-family: dejavusans;">DejaVu Sans — Extended Coverage</h2>
|
||||
<p style="font-family: dejavusans; font-size: 10pt;">
|
||||
DejaVu Sans covers Latin, Greek, Cyrillic, Armenian, Georgian, Hebrew,
|
||||
Arabic (basic), and many more. Use it when helvetica glyphs are missing.
|
||||
</p>
|
||||
<h3 style="font-family: dejavusans;">Latin Extended</h3>
|
||||
<p style="font-family: dejavusans; font-size: 11pt;">
|
||||
Héllo Wörld — café, naïve, résumé, Ångström, façade, Ñoño.
|
||||
</p>
|
||||
<h3 style="font-family: dejavusans;">Greek (Ελληνικά)</h3>
|
||||
<p style="font-family: dejavusans; font-size: 11pt;">
|
||||
Ξεσκεπάζω την ψυχοφθόρα βδελυγμία.
|
||||
</p>
|
||||
<h3 style="font-family: dejavusans;">Cyrillic (Русский)</h3>
|
||||
<p style="font-family: dejavusans; font-size: 11pt;">
|
||||
Съешь же ещё этих мягких французских булок, да выпей чаю.
|
||||
</p>
|
||||
<h3 style="font-family: dejavusans;">IPA Phonetics</h3>
|
||||
<p style="font-family: dejavusans; font-size: 11pt;">
|
||||
/ˌɪntəˈnæʃənl/ · /fəˈnɛtɪk/ · /ˈælfəbɪt/
|
||||
</p>
|
||||
<hr/>
|
||||
<p style="font-family: dejavusans; font-size: 9pt; color: #555555;">
|
||||
Subset tip: dejavusans is ~750 KB uncompressed. With <code>$subsetfont = true</code> and
|
||||
only the glyphs used in this page, the embedded subset would be much smaller.
|
||||
For documents mixing many scripts across many pages, subset embedding is recommended.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $dejavuHtml, posx: 15, posy: 20, width: 175);
|
||||
|
||||
// ===| Page 3 – Unifont: Full BMP |==========================================
|
||||
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
$pdf->page->addContent($fUnifont['out']);
|
||||
|
||||
$unifontHtml = '<h2 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Unifont — Full Unicode BMP Coverage</h2>
|
||||
<p style="font-family: unifont; font-size: 11pt;">
|
||||
Unifont offers very broad Unicode Plane 0 (BMP) coverage.
|
||||
Use it as a last-resort fallback for scripts not covered by DejaVu.
|
||||
Production PDFs should always use <code>$subsetfont = true</code> with Unifont.
|
||||
</p>
|
||||
<h3 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Arabic (العربية) — RTL</h3>
|
||||
<p style="font-family: unifont; font-size: 11pt; text-align: right;">
|
||||
صِف خَلقَ خَودِكِ كَمِثلِ الشَّمسِ إِذ بَزَغَت
|
||||
</p>
|
||||
<h3 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Hebrew (עברית) — RTL</h3>
|
||||
<p style="font-family: unifont; font-size: 11pt; text-align: right;">
|
||||
דג סקרן שט בים מאוכזב ולפתע מצא חברה
|
||||
</p>
|
||||
<h3 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Devanagari (हिन्दी)</h3>
|
||||
<p style="font-family: unifont; font-size: 11pt;">
|
||||
ऋषि सुयश ने प्रख्यात ग्रंथ की रचना करके हमें ज्ञान दिया।
|
||||
</p>
|
||||
<hr/>
|
||||
<p style="font-family: unifont; font-size: 11pt; color: #555555;">
|
||||
Fallback strategy: attempt to render with the most specific font first.
|
||||
Only escalate to Unifont for code points absent from narrower families.
|
||||
This minimises file size while ensuring every glyph is available.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $unifontHtml, posx: 15, posy: 20, width: 175);
|
||||
|
||||
// ----------
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E053_spot_overprint_proof.php
|
||||
*
|
||||
* Demonstrates spot color registration, tint ramp generation, and
|
||||
* overprint simulation using tc-lib-color and tc-lib-pdf-graph.
|
||||
*
|
||||
* What this demonstrates:
|
||||
* - color->addSpotColor(): register named spot colors with CMYK equivalents.
|
||||
* - color->getPdfColor($name, $stroke, $tint): apply spot ink at any tint level.
|
||||
* - Tint ramps: a sequence of filled rectangles stepping from 0% to 100% tint.
|
||||
* - Layered spot rectangles: simulate overprint by stacking semi-transparent shapes.
|
||||
* - Companion lib: tc-lib-color (spot/Lab color model), tc-lib-pdf-graph (rects).
|
||||
*
|
||||
* Note: tc-lib-pdf does not expose a native /OP (overprint) ExtGState toggle.
|
||||
* Overprint simulation here uses stacked shapes with varying tints to give a
|
||||
* visual impression of ink mixing, which is representative for screen proofing.
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 053');
|
||||
$pdf->setTitle('Spot Color & Overprint Proof');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf spot color CMYK tint ramp overprint proof');
|
||||
$pdf->setPDFFilename('053_spot_overprint_proof.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Register spot colors with CMYK fallback values.
|
||||
// These simulate industry-standard spot-like named inks. In a real press
|
||||
// workflow the names would match the RIP spot-color library exactly.
|
||||
|
||||
$pdf->color->addSpotColor('PROOF Cyan', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 1.0,
|
||||
'magenta' => 0.0,
|
||||
'yellow' => 0.0,
|
||||
'key' => 0.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('PROOF Magenta', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.0,
|
||||
'magenta' => 1.0,
|
||||
'yellow' => 0.0,
|
||||
'key' => 0.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('PROOF Yellow', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.0,
|
||||
'magenta' => 0.0,
|
||||
'yellow' => 1.0,
|
||||
'key' => 0.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('PROOF Black', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.0,
|
||||
'magenta' => 0.0,
|
||||
'yellow' => 0.0,
|
||||
'key' => 1.0,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('PROOF Warm Red', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.0,
|
||||
'magenta' => 0.85,
|
||||
'yellow' => 0.9,
|
||||
'key' => 0.02,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
$pdf->color->addSpotColor('PROOF Reflex Blue', new \Com\Tecnick\Color\Model\Cmyk([
|
||||
'cyan' => 0.93,
|
||||
'magenta' => 0.75,
|
||||
'yellow' => 0.0,
|
||||
'key' => 0.02,
|
||||
'alpha' => 0.0,
|
||||
]));
|
||||
|
||||
// ----------
|
||||
|
||||
$labelFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 8);
|
||||
$noteFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 8);
|
||||
|
||||
// ===| Page 1 – Tint Ramps |=================================================
|
||||
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
$pdf->page->addContent($labelFont['out']);
|
||||
|
||||
$introHtml = '<h1 style="font-family: helvetica;">Spot Color Proof — Tint Ramps</h1>
|
||||
<p style="font-family: helvetica; font-size: 9pt;">
|
||||
Each row shows a named spot color at tints from 10% to 100%.
|
||||
Spot colors are registered via <code>color->addSpotColor()</code> with a CMYK equivalent
|
||||
and applied using <code>color->getPdfColor($name, $stroke, $tint)</code>.
|
||||
The label column shows the spot name as it would appear in a PDF color dictionary.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $introHtml, posx: 15, posy: 20, width: 175);
|
||||
|
||||
// List of spots to render and their display label color
|
||||
/** @var array<int, array{name: string, label: string}> $spotRows */
|
||||
$spotRows = [
|
||||
['name' => 'PROOF Cyan', 'label' => '#007799'],
|
||||
['name' => 'PROOF Magenta', 'label' => '#990077'],
|
||||
['name' => 'PROOF Yellow', 'label' => '#887700'],
|
||||
['name' => 'PROOF Black', 'label' => '#222222'],
|
||||
['name' => 'PROOF Warm Red', 'label' => '#993300'],
|
||||
['name' => 'PROOF Reflex Blue', 'label' => '#001177'],
|
||||
];
|
||||
|
||||
$tintSteps = 10;
|
||||
$swatchW = 14.0;
|
||||
$swatchH = 10.0;
|
||||
$labelW = 42.0;
|
||||
$rowGap = 2.0;
|
||||
$startX = 15.0;
|
||||
$startY = 55.0;
|
||||
|
||||
// Draw tint scale header
|
||||
$pdf->page->addContent($noteFont['out']);
|
||||
for ($t = 1; $t <= $tintSteps; $t++) {
|
||||
$tx = $startX + $labelW + (($t - 1) * $swatchW);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: (string) ($t * 10) . '%',
|
||||
posx: $tx,
|
||||
posy: $startY - 5,
|
||||
width: $swatchW,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
}
|
||||
|
||||
$rowY = $startY;
|
||||
foreach ($spotRows as $row) {
|
||||
$spotName = $row['name'];
|
||||
$labelColor = $row['label'];
|
||||
|
||||
// Spot name label
|
||||
$pdf->page->addContent($labelFont['out']);
|
||||
$pdf->page->addContent($pdf->color->getPdfColor($labelColor, true, 1.0));
|
||||
$pdf->page->addContent($pdf->color->getPdfColor($labelColor, false, 1.0));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $spotName,
|
||||
posx: $startX,
|
||||
posy: $rowY + 2,
|
||||
width: $labelW,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Draw tint swatches 10%–100%
|
||||
for ($t = 1; $t <= $tintSteps; $t++) {
|
||||
$tint = $t / $tintSteps;
|
||||
$sx = $startX + $labelW + (($t - 1) * $swatchW);
|
||||
|
||||
// Set fill and stroke to spot color at this tint level
|
||||
$pdf->page->addContent($pdf->color->getPdfColor($spotName, true, $tint));
|
||||
$pdf->page->addContent($pdf->color->getPdfColor($spotName, false, $tint));
|
||||
$pdf->page->addContent($pdf->graph->getRect($sx, $rowY, $swatchW, $swatchH, 'DF'));
|
||||
}
|
||||
|
||||
$rowY += $swatchH + $rowGap;
|
||||
}
|
||||
|
||||
// Reset to black for subsequent text
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black', true, 1.0));
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black', false, 1.0));
|
||||
|
||||
$pdf->page->addContent($noteFont['out']);
|
||||
$footNote = '<p style="font-family: helvetica; font-size: 8pt; color: #555555; margin-top: 4mm;">
|
||||
Spot colors use the PDF <em>Separation</em> color space with a CMYK alternate.
|
||||
Screen rendering uses the CMYK alternate; print output uses the named ink.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $footNote, posx: 15, posy: 170, width: 175);
|
||||
|
||||
// ===| Page 2 – Stacked Spot Layers (Overprint Simulation) |=================
|
||||
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
$pdf->page->addContent($labelFont['out']);
|
||||
|
||||
$overHtml = '<h1 style="font-family: helvetica;">Overprint Simulation — Stacked Spot Layers</h1>
|
||||
<p style="font-family: helvetica; font-size: 9pt;">
|
||||
Two spot inks are drawn in overlapping rectangles at varying tints to simulate
|
||||
the visual effect of overprinting. In a real press workflow the RIP controls overprint
|
||||
behaviour via the <em>/OP</em> and <em>/op</em> ExtGState flags.
|
||||
This page shows the CMYK-alternate screen rendering of the overlap.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $overHtml, posx: 15, posy: 20, width: 175);
|
||||
|
||||
// Overprint grid: every combination of Cyan × Magenta at 25/50/75/100% tints
|
||||
$ox = 25.0;
|
||||
$oy = 55.0;
|
||||
$cellSize = 22.0;
|
||||
$tints = [0.25, 0.5, 0.75, 1.0];
|
||||
$labelNames = ['25%', '50%', '75%', '100%'];
|
||||
|
||||
// Column headers (Cyan tint)
|
||||
$pdf->page->addContent($labelFont['out']);
|
||||
foreach ($labelNames as $ci => $clab) {
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'C ' . $clab,
|
||||
posx: $ox + 12 + ($ci * $cellSize),
|
||||
posy: $oy - 7,
|
||||
width: $cellSize,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($tints as $mi => $mTint) {
|
||||
// Row header (Magenta tint)
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'M ' . $labelNames[$mi],
|
||||
posx: $ox,
|
||||
posy: $oy + ($mi * $cellSize) + 5,
|
||||
width: 12,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
foreach ($tints as $ci => $cTint) {
|
||||
$cx = $ox + 12 + ($ci * $cellSize);
|
||||
$cy = $oy + ($mi * $cellSize);
|
||||
|
||||
// Draw Cyan layer first, then Magenta layer on top
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('PROOF Cyan', false, $cTint));
|
||||
$pdf->page->addContent($pdf->graph->getRect($cx, $cy, $cellSize, $cellSize, 'F'));
|
||||
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('PROOF Magenta', false, $mTint));
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(0.6)); // partial alpha to show both layers
|
||||
$pdf->page->addContent($pdf->graph->getRect($cx, $cy, $cellSize, $cellSize, 'F'));
|
||||
$pdf->page->addContent($pdf->graph->getAlpha(1.0)); // restore
|
||||
}
|
||||
}
|
||||
|
||||
// Reset colors
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black', true, 1.0));
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black', false, 1.0));
|
||||
|
||||
$overNote = '<p style="font-family: helvetica; font-size: 8pt; color: #555555; margin-top: 4mm;">
|
||||
Each cell renders Cyan at the column tint, then Magenta at the row tint with 60% opacity —
|
||||
approximating a soft-proof of two overprinted inks on a white substrate.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $overNote, posx: 15, posy: 165, width: 175);
|
||||
|
||||
// ----------
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E054_page_groups_numbering.php
|
||||
*
|
||||
* Demonstrates publishing-style mixed page numbering: Roman-numeral front matter
|
||||
* followed by Arabic body pages, with a generated table of contents and
|
||||
* multi-level bookmarks as cross-reference anchors.
|
||||
*
|
||||
* What this demonstrates:
|
||||
* - setBookmark(): hierarchical outline entries with styles and colors.
|
||||
* - setNamedDestination(): stable jump targets independent of page order.
|
||||
* - addTOC(): auto-generated TOC page linked back to bookmarked sections.
|
||||
* - setDisplayMode(): open with outlines panel showing.
|
||||
* - Logical vs physical page numbering: inject visible Roman/Arabic labels
|
||||
* via page header content while the PDF page object index remains 0-based.
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 054');
|
||||
$pdf->setTitle('Page Groups & Mixed Numbering');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf page groups numbering roman arabic TOC bookmarks');
|
||||
$pdf->setPDFFilename('054_page_groups_numbering.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
// Open with the outline panel visible and full-width zoom.
|
||||
$pdf->setDisplayMode(
|
||||
zoom: \Com\Tecnick\Pdf\DisplayZoom::FullWidth,
|
||||
layout: \Com\Tecnick\Pdf\Page\PageLayout::SinglePage,
|
||||
mode: \Com\Tecnick\Pdf\Page\PageDisplayMode::UseOutlines,
|
||||
);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Fonts
|
||||
|
||||
$titleFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 16);
|
||||
$chFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
$bodyFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$smallFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
// ----------
|
||||
// Helpers
|
||||
|
||||
/** Convert an integer 1–3999 to an uppercase Roman numeral. */
|
||||
$toRoman = static function (int $n): string {
|
||||
$map = [
|
||||
1000 => 'M',
|
||||
900 => 'CM',
|
||||
500 => 'D',
|
||||
400 => 'CD',
|
||||
100 => 'C',
|
||||
90 => 'XC',
|
||||
50 => 'L',
|
||||
40 => 'XL',
|
||||
10 => 'X',
|
||||
9 => 'IX',
|
||||
5 => 'V',
|
||||
4 => 'IV',
|
||||
1 => 'I',
|
||||
];
|
||||
$result = '';
|
||||
foreach ($map as $val => $sym) {
|
||||
while ($n >= $val) {
|
||||
$result .= $sym;
|
||||
$n -= $val;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render a page number footer for the current page.
|
||||
* @param \Com\Tecnick\Pdf\Tcpdf $pdf
|
||||
* @param int $pid Page PID
|
||||
* @param string $label Visible page number string (e.g. "I", "1")
|
||||
* @param array{out: string} $font Font descriptor
|
||||
*/
|
||||
$addPageFooter = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, int $pid, string $label, array $font): void {
|
||||
$pdf->page->addContent($font['out'], $pid);
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell(
|
||||
txt: '— ' . $label . ' —',
|
||||
posx: 0,
|
||||
posy: 282,
|
||||
width: 210,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
),
|
||||
$pid,
|
||||
);
|
||||
};
|
||||
|
||||
// ===| FRONT MATTER |========================================================
|
||||
// Pages i, ii (TOC placeholder + Preface)
|
||||
// These pages use Roman numerals in the footer.
|
||||
|
||||
// ----- Page i: TOC placeholder -----
|
||||
$tocPage = $pdf->addPage(['format' => 'A4']);
|
||||
$pdf->setBookmark(
|
||||
name: 'Table of Contents',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: $tocPage['pid'],
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: 'gray',
|
||||
);
|
||||
$addPageFooter($pdf, $tocPage['pid'], $toRoman(1), $smallFont);
|
||||
|
||||
// Reserve header text for this page
|
||||
$pdf->page->addContent($titleFont['out'], $tocPage['pid']);
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell(
|
||||
txt: 'TABLE OF CONTENTS',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
),
|
||||
$tocPage['pid'],
|
||||
);
|
||||
// The actual TOC content is injected by addTOC() at the end of the script.
|
||||
|
||||
// ----- Page ii: Preface -----
|
||||
$prefacePage = $pdf->addPage(['format' => 'A4']);
|
||||
$pdf->setBookmark(
|
||||
name: 'Preface',
|
||||
link: '',
|
||||
level: 0,
|
||||
page: $prefacePage['pid'],
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: '',
|
||||
color: 'gray',
|
||||
);
|
||||
$addPageFooter($pdf, $prefacePage['pid'], $toRoman(2), $smallFont);
|
||||
|
||||
$prefaceHtml = '<h2 style="font-family: helvetica; text-align: center;">Preface</h2>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
This document demonstrates mixed page numbering conventions used in publishing workflows.
|
||||
Front matter (title, preface, table of contents) carries Roman numerals (i, ii, iii …),
|
||||
while the body text uses Arabic numerals (1, 2, 3 …).
|
||||
</p>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">
|
||||
In tc-lib-pdf, both logical page numbers displayed in footers and structural bookmarks are
|
||||
controlled independently. The PDF page object index is always zero-based; the visible label
|
||||
is rendered as regular text content. Named destinations remain stable regardless of the
|
||||
visible numbering scheme.
|
||||
</p>';
|
||||
$pdf->addHTMLCell(html: $prefaceHtml, posx: 15, posy: 30, width: 175, height: $prefacePage['pid']);
|
||||
|
||||
// ===| BODY |================================================================
|
||||
// Chapters 1–3, Arabic page numbers 1–3
|
||||
|
||||
/** @var array<int, array{title: string, sub: list<string>, color: string, bodyText: string}> $chapters */
|
||||
$chapters = [
|
||||
[
|
||||
'title' => 'Chapter 1 — Foundations',
|
||||
'sub' => ['1.1 History', '1.2 Key Concepts'],
|
||||
'color' => '#1a3c6e',
|
||||
'bodyText' => 'This chapter introduces the foundational ideas. Page number 1 (Arabic) appears in the footer. The bookmark entry for this chapter points to this page via a named destination.',
|
||||
],
|
||||
[
|
||||
'title' => 'Chapter 2 — Methods',
|
||||
'sub' => ['2.1 Approach A', '2.2 Approach B'],
|
||||
'color' => '#1a6e3c',
|
||||
'bodyText' => 'This chapter details the methodology. Page number 2 (Arabic) appears below. Bookmark level-1 entries for subsections use the same page pid with a vertical offset.',
|
||||
],
|
||||
[
|
||||
'title' => 'Chapter 3 — Results',
|
||||
'sub' => ['3.1 Findings', '3.2 Conclusions'],
|
||||
'color' => '#6e1a1a',
|
||||
'bodyText' => 'Final chapter with results and conclusions. Page number 3 (Arabic). The TOC on page i links back to all three chapter bookmarks.',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($chapters as $idx => $ch) {
|
||||
$arabicNum = $idx + 1;
|
||||
$chPage = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
// Register named destination so TOC links are stable.
|
||||
$destName = $pdf->setNamedDestination(name: 'chapter-' . $arabicNum, page: $chPage['pid'], posx: 0, posy: 0);
|
||||
|
||||
// Top-level bookmark (bold, chapter color)
|
||||
$pdf->setBookmark(
|
||||
name: $ch['title'],
|
||||
link: $destName,
|
||||
level: 0,
|
||||
page: $chPage['pid'],
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
fstyle: 'B',
|
||||
color: $ch['color'],
|
||||
);
|
||||
|
||||
// Sub-section bookmarks (indented, normal weight)
|
||||
foreach ($ch['sub'] as $si => $subTitle) {
|
||||
$subY = 70.0 + ($si * 20.0);
|
||||
$pdf->setBookmark(
|
||||
name: $subTitle,
|
||||
link: '',
|
||||
level: 1,
|
||||
page: $chPage['pid'],
|
||||
posx: 0,
|
||||
posy: $subY,
|
||||
fstyle: '',
|
||||
color: $ch['color'],
|
||||
);
|
||||
}
|
||||
|
||||
// Page footer with Arabic numeral
|
||||
$addPageFooter($pdf, $chPage['pid'], (string) $arabicNum, $smallFont);
|
||||
|
||||
// Chapter content
|
||||
$chHtml =
|
||||
'<h2 style="font-family: helvetica; color: '
|
||||
. $ch['color']
|
||||
. ';">'
|
||||
. htmlspecialchars($ch['title'])
|
||||
. '</h2>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">'
|
||||
. htmlspecialchars($ch['bodyText'])
|
||||
. '</p>';
|
||||
foreach ($ch['sub'] as $subTitle) {
|
||||
$chHtml .=
|
||||
'<h3 style="font-family: helvetica; color: '
|
||||
. $ch['color']
|
||||
. ';">'
|
||||
. htmlspecialchars($subTitle)
|
||||
. '</h3>
|
||||
<p style="font-family: helvetica; font-size: 10pt;">Section content would go here.</p>';
|
||||
}
|
||||
$pdf->addHTMLCell(html: $chHtml, posx: 15, posy: 20, width: 175, height: $chPage['pid']);
|
||||
}
|
||||
|
||||
// ===| GENERATE TOC |========================================================
|
||||
// addTOC() injects the outline entries onto the reserved TOC page (page i),
|
||||
// starting at y=35 (below the "TABLE OF CONTENTS" heading).
|
||||
// It uses the current font for rendering — activate bodyFont first.
|
||||
|
||||
$pdf->page->addContent($bodyFont['out'], $tocPage['pid']);
|
||||
$pdf->addTOC(page: $tocPage['pid'], posx: 15, posy: 35, width: 175);
|
||||
|
||||
// ----------
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E055_page_reorder_booklet.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate page reordering using tc-lib-pdf-page's Page::move() method.
|
||||
*
|
||||
* Scenario:
|
||||
* - Add pages in "draft" logical order: Introduction, Appendix, Chapter 1, Chapter 2.
|
||||
* - After authoring, reorder so the final reading order is:
|
||||
* 1. Introduction, 2. Chapter 1, 3. Chapter 2, 4. Appendix
|
||||
* - Each page shows its original draft index vs. its final booklet position.
|
||||
* - A booklet-spread grid is drawn on a landscape summary page to show how pages
|
||||
* pair up for saddle-stitch imposition (spread 1: pages 4 & 1; spread 2: pages 2 & 3).
|
||||
*/
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 055');
|
||||
$pdf->setTitle('Page Reorder and Booklet Imposition');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example page reorder booklet imposition spread');
|
||||
$pdf->setPDFFilename('E055_page_reorder_booklet.pdf');
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// Insert default font before first page.
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Phase 1 – Author pages in draft order (Introduction, Appendix, Ch1, Ch2)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Page index 0 – Introduction
|
||||
$page0 = $pdf->addPage(['format' => 'A5']);
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Introduction',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: '(Draft index 0)',
|
||||
posx: 15,
|
||||
posy: 36,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Welcome to the tc-lib-pdf page-reorder demo. This page was authored first'
|
||||
. ' and will remain in position 0 after reordering.',
|
||||
posx: 15,
|
||||
posy: 46,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Page index 1 – Appendix (will be moved to the end later)
|
||||
$page1 = $pdf->addPage(['format' => 'A5']);
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Appendix',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: '(Draft index 1 – will move to index 3)',
|
||||
posx: 15,
|
||||
posy: 36,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'This Appendix page was authored second but belongs at the end.'
|
||||
. ' Page::move() will relocate it after Chapter 2.',
|
||||
posx: 15,
|
||||
posy: 46,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Page index 2 – Chapter 1
|
||||
$page2 = $pdf->addPage(['format' => 'A5']);
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Chapter 1',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: '(Draft index 2 – will move to index 1)',
|
||||
posx: 15,
|
||||
posy: 36,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Chapter 1 content. After reordering this becomes the second page (index 1),'
|
||||
. ' immediately after the Introduction.',
|
||||
posx: 15,
|
||||
posy: 46,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Page index 3 – Chapter 2
|
||||
$page3 = $pdf->addPage(['format' => 'A5']);
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Chapter 2',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: '(Draft index 3 – will move to index 2)',
|
||||
posx: 15,
|
||||
posy: 36,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Chapter 2 content. After reordering this becomes the third page (index 2),'
|
||||
. ' between Chapter 1 and the Appendix.',
|
||||
posx: 15,
|
||||
posy: 46,
|
||||
width: 120,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Phase 2 – Reorder using Page::move()
|
||||
//
|
||||
// Current order: [0:Intro] [1:Appendix] [2:Ch1] [3:Ch2]
|
||||
// Target order: [0:Intro] [1:Ch1] [2:Ch2] [3:Appendix]
|
||||
//
|
||||
// Step A: move Ch1 (index 2) to index 1 → [Intro, Ch1, Appendix, Ch2]
|
||||
// Step B: move Ch2 (now index 3) to index 2 → [Intro, Ch1, Ch2, Appendix]
|
||||
//
|
||||
// Note: Page::move() only moves a page to a LOWER (earlier) index.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
$pdf->page->move(2, 1);
|
||||
// Order is now: [0:Intro] [1:Ch1] [2:Appendix] [3:Ch2]
|
||||
|
||||
$pdf->page->move(3, 2);
|
||||
// Order is now: [0:Intro] [1:Ch1] [2:Ch2] [3:Appendix]
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Phase 3 – Booklet imposition summary page (A4 landscape)
|
||||
//
|
||||
// For a 4-page saddle-stitch booklet the imposition pairs are:
|
||||
// Physical sheet front: page 4 (right) | page 1 (left) → spread 1
|
||||
// Physical sheet back: page 2 (left) | page 3 (right) → spread 2
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
$summaryPage = $pdf->addPage(['format' => 'A4', 'orientation' => 'L']);
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Booklet Imposition Summary (saddle-stitch, 4 pages)',
|
||||
posx: 15,
|
||||
posy: 12,
|
||||
width: 260,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// Draw spread grid
|
||||
$graph = $pdf->graph;
|
||||
|
||||
// Spread 1 – outer sheet (pages 4 & 1)
|
||||
$spread1X = 15.0;
|
||||
$spread1Y = 30.0;
|
||||
$spreadW = 118.0;
|
||||
$spreadH = 75.0;
|
||||
$halfW = $spreadW / 2;
|
||||
|
||||
// outer spread box
|
||||
$pdf->page->addContent($graph->getRect($spread1X, $spread1Y, $spreadW, $spreadH, 'D', [], []));
|
||||
// centre fold line
|
||||
$pdf->page->addContent($graph->getLine($spread1X + $halfW, $spread1Y, $spread1X + $halfW, $spread1Y + $spreadH));
|
||||
// labels
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Spread 1 – Outer sheet',
|
||||
posx: $spread1X,
|
||||
posy: $spread1Y - 6,
|
||||
width: $spreadW,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Page 4 (Appendix)',
|
||||
posx: $spread1X + 2,
|
||||
posy: $spread1Y + 4,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Right side of sheet',
|
||||
posx: $spread1X + 2,
|
||||
posy: $spread1Y + 12,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Page 1 (Introduction)',
|
||||
posx: $spread1X + $halfW + 2,
|
||||
posy: $spread1Y + 4,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Left side of sheet',
|
||||
posx: $spread1X + $halfW + 2,
|
||||
posy: $spread1Y + 12,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Spread 2 – inner sheet (pages 2 & 3)
|
||||
$spread2X = $spread1X + $spreadW + 20.0;
|
||||
|
||||
$pdf->page->addContent($graph->getRect($spread2X, $spread1Y, $spreadW, $spreadH, 'D', [], []));
|
||||
$pdf->page->addContent($graph->getLine($spread2X + $halfW, $spread1Y, $spread2X + $halfW, $spread1Y + $spreadH));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Spread 2 – Inner sheet',
|
||||
posx: $spread2X,
|
||||
posy: $spread1Y - 6,
|
||||
width: $spreadW,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Page 2 (Chapter 1)',
|
||||
posx: $spread2X + 2,
|
||||
posy: $spread1Y + 4,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Left side of sheet',
|
||||
posx: $spread2X + 2,
|
||||
posy: $spread1Y + 12,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Page 3 (Chapter 2)',
|
||||
posx: $spread2X + $halfW + 2,
|
||||
posy: $spread1Y + 4,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Right side of sheet',
|
||||
posx: $spread2X + $halfW + 2,
|
||||
posy: $spread1Y + 12,
|
||||
width: $halfW - 4,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Fold / cut annotation
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Fold along centre fold lines, then saddle-stitch through the fold.'
|
||||
. ' The final reading order after binding: Introduction → Chapter 1 → Chapter 2 → Appendix.',
|
||||
posx: 15,
|
||||
posy: 120,
|
||||
width: 260,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Output
|
||||
// -----------------------------------------------------------------------
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E056_encryption_cert_recipients.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate certificate-based (public-key) PDF encryption with a permission matrix.
|
||||
*
|
||||
* Certificate-based encryption lets you define a list of recipients; each recipient's
|
||||
* public-key certificate is used to wrap the document key. Only holders of the
|
||||
* corresponding private key can decrypt the document. No shared password is required.
|
||||
*
|
||||
* The example creates two logical recipients from the same demo certificate to show
|
||||
* how different permission sets can be defined per-recipient:
|
||||
* Recipient A – read-only (print only)
|
||||
* Recipient B – reviewer (print + annotate)
|
||||
*
|
||||
* The demo certificate shipped with the examples is a self-signed X.509 cert.
|
||||
* To create your own certificate:
|
||||
* openssl req -x509 -nodes -days 365000 -newkey rsa:2048 \
|
||||
* -keyout cert.pem -out cert.pem
|
||||
*/
|
||||
|
||||
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
|
||||
if ($certPath === false) {
|
||||
throw new \RuntimeException('Missing demo certificate: examples/data/cert/tcpdf.crt');
|
||||
}
|
||||
|
||||
$certUri = 'file://' . $certPath;
|
||||
|
||||
$mode = PHP_SAPI === 'cli' ? 'encrypted' : 'preview';
|
||||
if (PHP_SAPI === 'cli') {
|
||||
$mode = (string) ($argv[1] ?? 'encrypted');
|
||||
} elseif (isset($_GET['mode']) && \is_string($_GET['mode'])) {
|
||||
$mode = $_GET['mode'];
|
||||
}
|
||||
|
||||
$mode = \strtolower(\trim($mode));
|
||||
if (!\in_array($mode, ['encrypted', 'preview'], true)) {
|
||||
$mode = PHP_SAPI === 'cli' ? 'encrypted' : 'preview';
|
||||
}
|
||||
|
||||
$useEncryption = $mode === 'encrypted';
|
||||
|
||||
// Build recipient list:
|
||||
// Each entry has 'c' (certificate path/URI) and 'p' (allowed permissions array).
|
||||
$pubkeys = [
|
||||
[
|
||||
'c' => $certUri,
|
||||
'p' => ['print'], // Recipient A: print-only
|
||||
],
|
||||
[
|
||||
'c' => $certUri,
|
||||
'p' => ['print', 'annot-forms'], // Recipient B: print + annotate
|
||||
],
|
||||
];
|
||||
|
||||
$fileId = \md5('E056_encryption_cert_recipients');
|
||||
|
||||
$encrypt = null;
|
||||
if ($useEncryption) {
|
||||
// AES-128 (mode 2) with certificate recipients – no shared password needed.
|
||||
$encrypt = new \Com\Tecnick\Pdf\Encrypt\Encrypt(
|
||||
true, // enabled
|
||||
$fileId,
|
||||
2, // mode: AES-128
|
||||
[], // global permissions (empty – controlled per-recipient)
|
||||
'', // no user password
|
||||
'', // no owner password
|
||||
$pubkeys, // certificate recipients
|
||||
true, // encryptMetadata
|
||||
true, // encryptEmbeddedFiles
|
||||
);
|
||||
}
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: $encrypt,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 056');
|
||||
$pdf->setTitle('Certificate-Based Recipient Encryption');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example encryption certificate recipients public-key');
|
||||
$pdf->setPDFFilename('E056_encryption_cert_recipients.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 12);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 1 – Overview
|
||||
// -----------------------------------------------------------------------
|
||||
$page1 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Certificate-Based Recipient Encryption',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$html = <<<HTML
|
||||
<p><b>How it works</b></p>
|
||||
<p>Certificate-based encryption (also called <em>public-key encryption</em>) wraps the
|
||||
document encryption key using each recipient's X.509 public-key certificate.
|
||||
No shared password is distributed; only the holder of the matching private key can
|
||||
open the document.</p>
|
||||
|
||||
<p><b>Recipient permission matrix</b></p>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<th>Recipient</th>
|
||||
<th>Certificate</th>
|
||||
<th>Allowed permissions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Recipient A (read-only)</td>
|
||||
<td>tcpdf.crt (demo)</td>
|
||||
<td>print</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Recipient B (reviewer)</td>
|
||||
<td>tcpdf.crt (demo)</td>
|
||||
<td>print, annot-forms</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p><b>Encryption parameters</b></p>
|
||||
<ul>
|
||||
<li>Output mode: MODE_PLACEHOLDER</li>
|
||||
<li>Algorithm: AES-128 (mode 2) when mode is <em>encrypted</em></li>
|
||||
<li>Metadata encrypted: yes (encrypted mode)</li>
|
||||
<li>Embedded files encrypted: yes (encrypted mode)</li>
|
||||
<li>User/owner password: none (certificate recipients only, encrypted mode)</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Creating your own certificate</b></p>
|
||||
<p>Use the following OpenSSL command to generate a self-signed certificate suitable for
|
||||
recipient encryption:</p>
|
||||
<p><em>openssl req -x509 -nodes -days 365000 -newkey rsa:2048 -keyout cert.pem -out cert.pem</em></p>
|
||||
HTML;
|
||||
|
||||
$modeLabel = $useEncryption ? 'encrypted (certificate recipients)' : 'preview (unencrypted for browser compatibility)';
|
||||
|
||||
$html = \str_replace('MODE_PLACEHOLDER', $modeLabel, $html);
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 30, width: 180);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 2 – Permissions reference
|
||||
// -----------------------------------------------------------------------
|
||||
$page2 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'PDF Permission Flags Reference',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$html2 = <<<HTML
|
||||
<p><b>Available permission identifiers</b></p>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr><th>Identifier</th><th>Description</th></tr>
|
||||
<tr><td>print</td><td>Print the document (low-quality).</td></tr>
|
||||
<tr><td>modify</td><td>Modify document content (not covered by more specific flags).</td></tr>
|
||||
<tr><td>copy</td><td>Copy or extract text and graphics.</td></tr>
|
||||
<tr><td>annot-forms</td><td>Add/modify annotations and fill interactive forms.</td></tr>
|
||||
<tr><td>fill-forms</td><td>Fill in existing interactive form fields.</td></tr>
|
||||
<tr><td>extract</td><td>Extract content for accessibility.</td></tr>
|
||||
<tr><td>assemble</td><td>Insert/rotate/delete pages, create bookmarks and thumbnails.</td></tr>
|
||||
<tr><td>print-high</td><td>Print at high quality (faithful digital reproduction).</td></tr>
|
||||
</table>
|
||||
|
||||
<p><b>Notes</b></p>
|
||||
<ul>
|
||||
<li>With certificate recipients, permission flags are embedded inside the CMS enveloped-data
|
||||
structure for each recipient separately.</li>
|
||||
<li>Viewer enforcement of permissions depends on the PDF reader implementation.</li>
|
||||
<li>Combining certificate encryption with a digital signature (E057) provides both
|
||||
access control and document integrity assurance.</li>
|
||||
</ul>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html2, posx: 15, posy: 30, width: 180);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Output
|
||||
// -----------------------------------------------------------------------
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
if ($useEncryption) {
|
||||
// Most browser-native PDF viewers do not support certificate-based decryption.
|
||||
// Force a download so the file can be opened with a compatible PDF reader.
|
||||
$pdf->downloadPDF(rawpdf: $rawpdf);
|
||||
exit();
|
||||
}
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
exit();
|
||||
}
|
||||
|
||||
echo $rawpdf;
|
||||
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E057_multisignature_incremental.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate a multi-signature approval flow.
|
||||
*
|
||||
* In a real approval workflow a document typically accumulates one signature
|
||||
* per approver in sequence (incremental signatures). tc-lib-pdf supports this
|
||||
* pattern by:
|
||||
*
|
||||
* 1. setSignature() – primary signing certificate (author / certifier)
|
||||
* 2. setSignatureAppearance() – visible widget for the primary signature
|
||||
* 3. addEmptySignatureAppearance() – empty widget placeholders for each subsequent approver
|
||||
*
|
||||
* The primary signature field (cert_type 2 = MDP/Author) locks the document
|
||||
* against further modifications while still permitting subsequent approvals to
|
||||
* fill in the reserved empty fields.
|
||||
*
|
||||
* This example creates a 3-page document:
|
||||
* Page 1 – contract / document body
|
||||
* Page 2 – approval form with 3 signature fields:
|
||||
* · Author (primary – pre-signed by the library)
|
||||
* · Reviewer (empty approval field)
|
||||
* · Manager (empty approval field)
|
||||
* Page 3 – signing guide / workflow description
|
||||
*/
|
||||
|
||||
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
|
||||
if ($certPath === false) {
|
||||
throw new \RuntimeException('Missing signing certificate: examples/data/cert/tcpdf.crt');
|
||||
}
|
||||
|
||||
$cert = 'file://' . $certPath;
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 057');
|
||||
$pdf->setTitle('Multi-Signature Approval Flow');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example signature approval multi-signature incremental');
|
||||
$pdf->setPDFFilename('E057_multisignature_incremental.pdf');
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 12);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 1 – Document body (contract)
|
||||
// -----------------------------------------------------------------------
|
||||
$page1 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'SERVICE AGREEMENT EXAMPLE',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$html1 = <<<HTML
|
||||
<p>This Service Agreement ("Agreement") is entered into as of the date of the last signature below
|
||||
between <strong>Client</strong> and <strong>Service Provider</strong>.</p>
|
||||
|
||||
<p><b>1. Services.</b> Service Provider agrees to deliver software development services as described
|
||||
in Schedule A attached hereto.</p>
|
||||
|
||||
<p><b>2. Payment.</b> Client agrees to pay the fees set forth in Schedule B within 30 days of invoice.</p>
|
||||
|
||||
<p><b>3. Term.</b> This Agreement commences on the Effective Date and continues for 12 months unless
|
||||
earlier terminated by either party upon 30 days written notice.</p>
|
||||
|
||||
<p><b>4. Confidentiality.</b> Each party agrees to keep the other party's confidential information
|
||||
strictly confidential and not to disclose it to any third party without prior written consent.</p>
|
||||
|
||||
<p><b>5. Governing Law.</b> This Agreement shall be governed by the laws of the applicable jurisdiction.</p>
|
||||
|
||||
<p>The parties have executed this Agreement as of the dates indicated in the signature fields on
|
||||
the following page.</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html1, posx: 15, posy: 30, width: 180);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 2 – Approval / signature form
|
||||
// -----------------------------------------------------------------------
|
||||
$page2 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'SIGNATURE PAGE EXAMPLE',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'The following parties have reviewed and approved this Agreement:',
|
||||
posx: 15,
|
||||
posy: 30,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Signature box helper labels (rendered as PDF text cells)
|
||||
$labels = [
|
||||
['role' => 'Author / Certifier', 'name' => 'John Doe', 'y' => 45],
|
||||
['role' => 'Reviewer', 'name' => '(awaiting sig.)', 'y' => 90],
|
||||
['role' => 'Manager', 'name' => '(awaiting sig.)', 'y' => 135],
|
||||
];
|
||||
|
||||
foreach ($labels as $lbl) {
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $lbl['role'],
|
||||
posx: 15,
|
||||
posy: (float) $lbl['y'],
|
||||
width: 85,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Name: ' . $lbl['name'],
|
||||
posx: 15,
|
||||
posy: (float) ($lbl['y'] + 7),
|
||||
width: 85,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Date: ___________________',
|
||||
posx: 15,
|
||||
posy: (float) ($lbl['y'] + 14),
|
||||
width: 85,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Register the primary (author/certifier) digital signature.
|
||||
// cert_type = 2 → MDP / author signature
|
||||
// -----------------------------------------------------------------------
|
||||
$pdf->setSignature([
|
||||
'cert_type' => 2,
|
||||
'info' => [
|
||||
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
'Location' => 'Demo Office',
|
||||
'Name' => 'John Doe',
|
||||
'Reason' => 'Author / certifier signature – approval workflow example',
|
||||
],
|
||||
'password' => '',
|
||||
'privkey' => $cert,
|
||||
'signcert' => $cert,
|
||||
]);
|
||||
|
||||
// Primary signature appearance – placed on page 2 at the first slot.
|
||||
$pdf->setSignatureAppearance(posx: 100, posy: 45, width: 90, height: 35, page: $page2['pid'], name: 'Author');
|
||||
|
||||
// Empty approval fields for the remaining approvers.
|
||||
$pdf->addEmptySignatureAppearance(posx: 100, posy: 90, width: 90, height: 35, page: $page2['pid'], name: 'Reviewer');
|
||||
$pdf->addEmptySignatureAppearance(posx: 100, posy: 135, width: 90, height: 35, page: $page2['pid'], name: 'Manager');
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 3 – Workflow guide
|
||||
// -----------------------------------------------------------------------
|
||||
$page3 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Multi-Signature Workflow Guide',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$html3 = <<<HTML
|
||||
<p><b>How incremental multi-signature works in tc-lib-pdf</b></p>
|
||||
|
||||
<p>A PDF approval workflow typically progresses through these steps:</p>
|
||||
<ol>
|
||||
<li><b>Author creates and certifies the document.</b>
|
||||
The primary signature (Author field) is applied by <code>setSignature()</code> with
|
||||
<em>cert_type 2</em> (MDP). This locks the document against structural changes
|
||||
while reserving the empty approval fields for subsequent signers.</li>
|
||||
|
||||
<li><b>Reviewer opens the document, validates the Author signature, and applies their
|
||||
signature to the Reviewer field.</b> In a PDF viewer (e.g. Acrobat) the reviewer
|
||||
uses the reserved empty widget. Each subsequent signature is appended to the file
|
||||
as an incremental update, preserving all prior signature data.</li>
|
||||
|
||||
<li><b>Manager repeats the same process for the Manager field.</b></li>
|
||||
</ol>
|
||||
|
||||
<p><b>tc-lib-pdf API summary</b></p>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr><th>Method</th><th>Purpose</th></tr>
|
||||
<tr><td>setSignature()</td><td>Register the primary signing certificate and options.</td></tr>
|
||||
<tr><td>setSignatureAppearance()</td><td>Visible widget for the primary signature.</td></tr>
|
||||
<tr><td>addEmptySignatureAppearance()</td><td>Reserve an empty widget for a future approver.</td></tr>
|
||||
<tr><td>setSignTimeStamp()</td><td>Optionally attach an RFC 3161 TSA timestamp (see E008).</td></tr>
|
||||
</table>
|
||||
|
||||
<p><b>Certification levels (cert_type)</b></p>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr><th>cert_type</th><th>Meaning</th></tr>
|
||||
<tr><td>1</td><td>No changes permitted after signing.</td></tr>
|
||||
<tr><td>2</td><td>Form fills and approval signatures permitted (MDP).</td></tr>
|
||||
<tr><td>3</td><td>Annotations and form fills permitted.</td></tr>
|
||||
</table>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html3, posx: 15, posy: 30, width: 180);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Output
|
||||
// -----------------------------------------------------------------------
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E058_embedded_files_portfolio.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate PDF as a document container (portfolio / package).
|
||||
*
|
||||
* Multiple file types are embedded inside the PDF using:
|
||||
* addEmbeddedFile() – embed a file from disk
|
||||
* addContentAsEmbeddedFile() – embed content generated in-memory (CSV, XML, JSON)
|
||||
*
|
||||
* Each embedded file is then linked to an annotation on the document page so
|
||||
* that clicking the annotation in a viewer opens or exports the attachment.
|
||||
*
|
||||
* Embedded files:
|
||||
* invoice.csv – tabular invoice data
|
||||
* report.xml – XML report
|
||||
* config.json – JSON configuration
|
||||
*/
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 058');
|
||||
$pdf->setTitle('Embedded Files Portfolio');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example embedded files portfolio attachment csv xml json');
|
||||
$pdf->setPDFFilename('E058_embedded_files_portfolio.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 12);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build the in-memory attachment content
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
$csvContent = <<<CSV
|
||||
item_no,description,qty,unit_price,total
|
||||
1,"Widget A",10,9.99,99.90
|
||||
2,"Widget B",5,24.50,122.50
|
||||
3,"Service Fee",1,150.00,150.00
|
||||
,,,,
|
||||
,,"Subtotal",,372.40
|
||||
,,"Tax (10%)",,37.24
|
||||
,,"Total",,409.64
|
||||
CSV;
|
||||
|
||||
$xmlContent = <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report generated="2026-05-01" version="1.0">
|
||||
<summary>
|
||||
<title>Monthly Sales Report</title>
|
||||
<period>April 2026</period>
|
||||
<currency>USD</currency>
|
||||
</summary>
|
||||
<items>
|
||||
<item id="1"><name>Widget A</name><qty>10</qty><revenue>99.90</revenue></item>
|
||||
<item id="2"><name>Widget B</name><qty>5</qty><revenue>122.50</revenue></item>
|
||||
<item id="3"><name>Service Fee</name><qty>1</qty><revenue>150.00</revenue></item>
|
||||
</items>
|
||||
<totals>
|
||||
<subtotal>372.40</subtotal>
|
||||
<tax>37.24</tax>
|
||||
<total>409.64</total>
|
||||
</totals>
|
||||
</report>
|
||||
XML;
|
||||
|
||||
$jsonContent = \json_encode(
|
||||
[
|
||||
'application' => 'tc-lib-pdf demo',
|
||||
'version' => '1.0',
|
||||
'settings' => [
|
||||
'compress' => true,
|
||||
'unicode' => true,
|
||||
'subset_fonts' => false,
|
||||
'pdf_version' => '1.7',
|
||||
],
|
||||
'output' => [
|
||||
'mode' => 'render',
|
||||
'filename' => 'E058_embedded_files_portfolio.pdf',
|
||||
],
|
||||
],
|
||||
\JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES,
|
||||
);
|
||||
|
||||
if ($jsonContent === false) {
|
||||
throw new \RuntimeException('Failed to encode JSON content');
|
||||
}
|
||||
|
||||
// Embed content generated in-memory
|
||||
$pdf->addContentAsEmbeddedFile(
|
||||
file: 'invoice.csv',
|
||||
content: $csvContent,
|
||||
mime: 'text/csv',
|
||||
afrel: \Com\Tecnick\Pdf\AFRelationship::Data,
|
||||
desc: 'Invoice line items',
|
||||
);
|
||||
$pdf->addContentAsEmbeddedFile(
|
||||
file: 'report.xml',
|
||||
content: $xmlContent,
|
||||
mime: 'application/xml',
|
||||
afrel: \Com\Tecnick\Pdf\AFRelationship::Data,
|
||||
desc: 'Monthly sales report',
|
||||
);
|
||||
$pdf->addContentAsEmbeddedFile(
|
||||
file: 'config.json',
|
||||
content: $jsonContent,
|
||||
mime: 'application/json',
|
||||
afrel: \Com\Tecnick\Pdf\AFRelationship::Source,
|
||||
desc: 'Library configuration',
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 1 – Portfolio overview
|
||||
// -----------------------------------------------------------------------
|
||||
$page1 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Embedded Files Portfolio',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$html = <<<HTML
|
||||
<p>This PDF acts as a self-contained package by embedding three data files in different formats.
|
||||
Click the annotation icons on this page (or use your PDF viewer's attachment panel) to
|
||||
access the files.</p>
|
||||
|
||||
<p><b>Embedded attachments</b></p>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr><th>Filename</th><th>MIME type</th><th>AFRelationship</th><th>Description</th></tr>
|
||||
<tr><td>invoice.csv</td><td>text/csv</td><td>Data</td><td>Invoice line items</td></tr>
|
||||
<tr><td>report.xml</td><td>application/xml</td><td>Data</td><td>Monthly sales report</td></tr>
|
||||
<tr><td>config.json</td><td>application/json</td><td>Source</td><td>Library configuration</td></tr>
|
||||
</table>
|
||||
|
||||
<p><b>API used</b></p>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr><th>Method</th><th>Use case</th></tr>
|
||||
<tr><td>addEmbeddedFile()</td><td>Embed a file read from disk.</td></tr>
|
||||
<tr><td>addContentAsEmbeddedFile()</td><td>Embed content generated in memory.</td></tr>
|
||||
<tr><td>setAnnotation() with Fileattachment subtype</td><td>Visible annotation linking to an embedded file.</td></tr>
|
||||
</table>
|
||||
|
||||
<p>The <em>AFRelationship</em> value categorises each attachment for PDF processors:
|
||||
<em>Source</em> = the source that produced this PDF; <em>Data</em> = data associated with the PDF.</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 30, width: 180);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Attachment annotations – link visible icons to each embedded file
|
||||
// Annotation type 'FileAttachment', opt 'fs' = file key, 'name' = icon name
|
||||
// -----------------------------------------------------------------------
|
||||
$annotations = [
|
||||
['file' => 'invoice.csv', 'label' => 'invoice.csv', 'x' => 15, 'y' => 175],
|
||||
['file' => 'report.xml', 'label' => 'report.xml', 'x' => 60, 'y' => 175],
|
||||
['file' => 'config.json', 'label' => 'config.json', 'x' => 105, 'y' => 175],
|
||||
];
|
||||
|
||||
foreach ($annotations as $ann) {
|
||||
$annotId = $pdf->setAnnotation(
|
||||
posx: (float) $ann['x'],
|
||||
posy: (float) $ann['y'],
|
||||
width: 40.0,
|
||||
height: 10.0,
|
||||
txt: (string) $ann['label'],
|
||||
opt: [
|
||||
'subtype' => 'FileAttachment',
|
||||
'fs' => $ann['file'],
|
||||
'name' => 'PushPin',
|
||||
'f' => 4,
|
||||
],
|
||||
);
|
||||
$pdf->page->addAnnotRef($annotId, $page1['pid']);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 2 – Content preview
|
||||
// -----------------------------------------------------------------------
|
||||
$page2 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfontB['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Attachment Content Preview',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$previewHtml = <<<HTML
|
||||
<p><b>invoice.csv (first few lines)</b></p>
|
||||
<pre>item_no,description,qty,unit_price,total
|
||||
1,"Widget A",10,9.99,99.90
|
||||
2,"Widget B",5,24.50,122.50
|
||||
3,"Service Fee",1,150.00,150.00</pre>
|
||||
|
||||
<p><b>report.xml (excerpt)</b></p>
|
||||
<pre><report generated="2026-05-01" version="1.0">
|
||||
<summary><title>Monthly Sales Report</title></summary>
|
||||
<totals>
|
||||
<subtotal>372.40</subtotal>
|
||||
<total>409.64</total>
|
||||
</totals>
|
||||
</report></pre>
|
||||
|
||||
<p><b>config.json (excerpt)</b></p>
|
||||
<pre>{
|
||||
"application": "tc-lib-pdf demo",
|
||||
"version": "1.0",
|
||||
"settings": {
|
||||
"compress": true,
|
||||
"unicode": true
|
||||
}
|
||||
}</pre>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $previewHtml, posx: 15, posy: 30, width: 180);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Output
|
||||
// -----------------------------------------------------------------------
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E059_document_javascript.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate document-level JavaScript actions.
|
||||
*
|
||||
* This example covers three distinct attachment mechanisms:
|
||||
*
|
||||
* appendRawJavaScript()
|
||||
* Appends raw JS to the single global script string. The global script
|
||||
* runs as a document-open action (equivalent to \WillSave / open trigger
|
||||
* in Acrobat JS terms). Useful for lightweight one-shot initialization
|
||||
* that must not duplicate logic across multiple calls.
|
||||
*
|
||||
* addRawJavaScriptObj($script, onload: true)
|
||||
* Creates a separate JS object that is executed when the document is
|
||||
* opened (document-level open action). Suitable for modular scripts
|
||||
* that need to be kept independent of the global string.
|
||||
*
|
||||
* addRawJavaScriptObj($script, onload: false)
|
||||
* Creates a JS object that is embedded but NOT wired as an open action.
|
||||
* It can be referenced by annotation actions or triggered programmatically
|
||||
* by other scripts (e.g. via a named action or a button field).
|
||||
*
|
||||
* NOTE: JavaScript is silently suppressed in PDF/A, PDF/X, and PDF/UA modes
|
||||
* because those standards forbid embedded scripts. This example therefore
|
||||
* uses plain (unconstrained) PDF output.
|
||||
*
|
||||
* NOTE: Script execution requires a PDF reader with Acrobat JavaScript support
|
||||
* (e.g. Adobe Acrobat / Adobe Reader). Many open-source readers do not run JS.
|
||||
*/
|
||||
|
||||
// main TCPDF object — plain mode (no PDF/A, PDF/X, PDF/UA constraint)
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 059');
|
||||
$pdf->setTitle('Document-Level JavaScript Actions');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example javascript document open close print save trigger');
|
||||
$pdf->setPDFFilename('E059_document_javascript.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 1. appendRawJavaScript — global JS string (document-open trigger)
|
||||
// -----------------------------------------------------------------------
|
||||
// The JS string is accumulated and emitted as a single named JS object
|
||||
// ("EmbeddedJS"). It fires when the document is opened.
|
||||
$pdf->appendRawJavaScript(script: 'app.alert("Document opened via appendRawJavaScript.", 3);' . "\n");
|
||||
|
||||
// Multiple calls are concatenated in order.
|
||||
$pdf->appendRawJavaScript(
|
||||
script: 'app.addStateChangeHandler("WillClose", function() {'
|
||||
. "\n"
|
||||
. ' app.alert("Document is closing (WillClose handler).", 3);'
|
||||
. "\n"
|
||||
. '});'
|
||||
. "\n",
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 2. addRawJavaScriptObj — separate JS object, executed on open
|
||||
// -----------------------------------------------------------------------
|
||||
// Returns the PDF object ID so you can cross-reference if needed.
|
||||
$onloadObjId = $pdf->addRawJavaScriptObj(
|
||||
// Register a WillPrint event to warn the user before printing.
|
||||
'app.addStateChangeHandler("WillPrint", function() {'
|
||||
. "\n"
|
||||
. ' app.alert("Document will be printed.", 3);'
|
||||
. "\n"
|
||||
. '});'
|
||||
. "\n",
|
||||
true, // onload: execute when the document is opened
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 3. addRawJavaScriptObj — separate JS object, NOT an open action
|
||||
// -----------------------------------------------------------------------
|
||||
// This object is embedded in the PDF but is NOT automatically executed.
|
||||
// A button field or annotation action can trigger it by name.
|
||||
$idleObjId = $pdf->addRawJavaScriptObj(
|
||||
// A utility helper function that can be called from other scripts.
|
||||
'function showDocInfo() {'
|
||||
. "\n"
|
||||
. ' var msg = "Title: " + this.info.Title + "\\n"'
|
||||
. "\n"
|
||||
. ' + "Author: " + this.info.Author;'
|
||||
. "\n"
|
||||
. ' app.alert(msg, 3);'
|
||||
. "\n"
|
||||
. '}'
|
||||
. "\n",
|
||||
false, // onload: false — NOT executed automatically
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 1 — Explanation
|
||||
// -----------------------------------------------------------------------
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
|
||||
$page1 = $pdf->addPage();
|
||||
|
||||
$html = <<<HTML
|
||||
<h1 style="font-size:16pt; color:#003366;">Document-Level JavaScript Actions</h1>
|
||||
<p style="font-size:10pt; color:#333333;">
|
||||
This PDF demonstrates three distinct ways to attach JavaScript to a document
|
||||
using tc-lib-pdf. The scripts are embedded in the PDF structure; a compatible
|
||||
reader with Acrobat JavaScript support is required to execute them.
|
||||
</p>
|
||||
<h2 style="font-size:13pt; color:#005599;">1. appendRawJavaScript()</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Appends raw JS to the global script string. The accumulated string fires when
|
||||
the document is opened. Two separate calls were made in this example: one to
|
||||
show an alert on open, and one to register a <code>WillClose</code> handler.
|
||||
</p>
|
||||
<h2 style="font-size:13pt; color:#005599;">2. addRawJavaScriptObj(\$script, onload: true)</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Creates a separate JS object (PDF object ID: <b>{$onloadObjId}</b>) and wires it as an
|
||||
open action so it executes when the document is opened. In this example the
|
||||
script registers a <code>WillPrint</code> event handler.
|
||||
</p>
|
||||
<h2 style="font-size:13pt; color:#005599;">3. addRawJavaScriptObj(\$script, onload: false)</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Creates a JS object (PDF object ID: <b>{$idleObjId}</b>) that is embedded but NOT
|
||||
executed automatically. It defines a helper function <code>showDocInfo()</code>
|
||||
that other scripts or button-field actions can invoke.
|
||||
</p>
|
||||
<h2 style="font-size:13pt; color:#005599;">Suppression in conformance modes</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
All three JS APIs silently return without effect when the PDF is created in
|
||||
PDF/A, PDF/X, or PDF/UA mode, because those standards forbid embedded scripts.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E060_custom_xmp_metadata.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate custom XMP namespace injection via setCustomXMP().
|
||||
*
|
||||
* PDF files carry an XMP metadata stream alongside the classic Info dictionary.
|
||||
* The tc-lib-pdf library always emits standard namespaces (dc:, xmp:, pdf:,
|
||||
* xmpMM:, pdfaid:, etc.). setCustomXMP() lets you inject arbitrary additional
|
||||
* XMP fragments into specific positions within the XMP envelope.
|
||||
*
|
||||
* Valid keys and their injection points
|
||||
* ──────────────────────────────────────
|
||||
* 'x:xmpmeta'
|
||||
* Inserted just before </x:xmpmeta> — top-level envelope extension.
|
||||
*
|
||||
* 'x:xmpmeta.rdf:RDF'
|
||||
* Inserted just before </rdf:RDF> — adds a new rdf:Description block.
|
||||
*
|
||||
* 'x:xmpmeta.rdf:RDF.rdf:Description'
|
||||
* Inserted into the main rdf:Description — adds properties to the
|
||||
* existing shared description block (dc, xmp, pdf properties).
|
||||
*
|
||||
* 'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas'
|
||||
* 'x:xmpmeta.rdf:RDF.rdf:Description.pdfaExtension:schemas.rdf:Bag'
|
||||
* PDF/A extension schema declarations (only meaningful in PDF/A mode).
|
||||
*
|
||||
* IMPORTANT: the injected XML is NOT validated by the library. You are
|
||||
* responsible for well-formed, namespace-correct XMP. Malformed XMP will
|
||||
* not prevent PDF generation but may confuse metadata readers.
|
||||
*
|
||||
* Use cases illustrated here:
|
||||
* 1. IPTC Core rights metadata (photojournalism / stock-photography DAM)
|
||||
* 2. XMP-MM version history (document management / DAM systems)
|
||||
* 3. Custom application metadata (arbitrary key-value pairs for integration)
|
||||
*/
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 060');
|
||||
$pdf->setTitle('Custom XMP Metadata Injection');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example xmp metadata iptc dublin core dam archiving');
|
||||
$pdf->setPDFFilename('E060_custom_xmp_metadata.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 1. IPTC Core rights and creator metadata
|
||||
// Injected as a new rdf:Description block inside rdf:RDF.
|
||||
// -----------------------------------------------------------------------
|
||||
$iptcXmp = <<<'XMP'
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/">
|
||||
<Iptc4xmpCore:CopyrightNotice>Copyright © 2026 Tecnick.com LTD. All rights reserved.</Iptc4xmpCore:CopyrightNotice>
|
||||
<Iptc4xmpCore:CreatorContactInfo>
|
||||
<rdf:Description>
|
||||
<Iptc4xmpCore:CiEmailWork>info@tecnick.com</Iptc4xmpCore:CiEmailWork>
|
||||
<Iptc4xmpCore:CiUrlWork>https://tecnick.com</Iptc4xmpCore:CiUrlWork>
|
||||
</rdf:Description>
|
||||
</Iptc4xmpCore:CreatorContactInfo>
|
||||
<Iptc4xmpCore:UsageTerms>
|
||||
<rdf:Alt>
|
||||
<rdf:li xml:lang="en">Permission is granted to reproduce for personal and commercial use,
|
||||
citing the source. Modification is not allowed.</rdf:li>
|
||||
</rdf:Alt>
|
||||
</Iptc4xmpCore:UsageTerms>
|
||||
</rdf:Description>
|
||||
|
||||
XMP;
|
||||
|
||||
// Key: inject before </rdf:RDF>
|
||||
$pdf->setCustomXMP('x:xmpmeta.rdf:RDF', $iptcXmp);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 2. XMP Media Management — version / revision history
|
||||
// Also injected as a new rdf:Description block.
|
||||
// -----------------------------------------------------------------------
|
||||
$xmpMmXmp = <<<'XMP'
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
|
||||
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
|
||||
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
|
||||
<xmpMM:DocumentID>urn:uuid:tc-lib-pdf-example-060-2026</xmpMM:DocumentID>
|
||||
<xmpMM:InstanceID>urn:uuid:tc-lib-pdf-example-060-instance-001</xmpMM:InstanceID>
|
||||
<xmpMM:VersionID>1.0</xmpMM:VersionID>
|
||||
<xmpMM:History>
|
||||
<rdf:Seq>
|
||||
<rdf:li rdf:parseType="Resource">
|
||||
<stEvt:action>created</stEvt:action>
|
||||
<stEvt:when>2026-05-01T00:00:00+00:00</stEvt:when>
|
||||
<stEvt:softwareAgent>tc-lib-pdf</stEvt:softwareAgent>
|
||||
</rdf:li>
|
||||
</rdf:Seq>
|
||||
</xmpMM:History>
|
||||
<xmpMM:DerivedFrom rdf:parseType="Resource">
|
||||
<stRef:documentID>urn:uuid:tc-lib-pdf-example-059-2026</stRef:documentID>
|
||||
<stRef:versionID>1.0</stRef:versionID>
|
||||
</xmpMM:DerivedFrom>
|
||||
</rdf:Description>
|
||||
|
||||
XMP;
|
||||
|
||||
$pdf->setCustomXMP('x:xmpmeta.rdf:RDF', $xmpMmXmp);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 3. Custom application metadata (key-value pairs for system integration)
|
||||
// Injected as extra properties in the existing shared rdf:Description.
|
||||
// -----------------------------------------------------------------------
|
||||
$appXmp = <<<'XMP'
|
||||
<tcpdf:exampleId>E060</tcpdf:exampleId>
|
||||
<tcpdf:generatedBy>tc-lib-pdf</tcpdf:generatedBy>
|
||||
<tcpdf:generationDate>2026-05-01</tcpdf:generationDate>
|
||||
|
||||
XMP;
|
||||
|
||||
// Note: this key injects into the existing shared rdf:Description block.
|
||||
// The tcpdf: prefix must be declared in the same Description or a parent.
|
||||
// For self-contained safety we wrap it in its own Description with the ns decl.
|
||||
$appXmpBlock = <<<'XMP'
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:tcpdf="https://github.com/tecnickcom/tc-lib-pdf/ns/xmp/1.0/">
|
||||
<tcpdf:exampleId>E060</tcpdf:exampleId>
|
||||
<tcpdf:generatedBy>tc-lib-pdf</tcpdf:generatedBy>
|
||||
<tcpdf:generationDate>2026-05-01</tcpdf:generationDate>
|
||||
<tcpdf:featureTag>custom-xmp-metadata</tcpdf:featureTag>
|
||||
</rdf:Description>
|
||||
|
||||
XMP;
|
||||
|
||||
$pdf->setCustomXMP('x:xmpmeta.rdf:RDF', $appXmpBlock);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page — explanation and key summary
|
||||
// -----------------------------------------------------------------------
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
|
||||
$page1 = $pdf->addPage();
|
||||
|
||||
$html = <<<'HTML'
|
||||
<h1 style="font-size:16pt; color:#003366;">Custom XMP Metadata Injection</h1>
|
||||
<p style="font-size:10pt; color:#333333;">
|
||||
This PDF embeds three custom XMP metadata blocks beyond the standard dc:/xmp:
|
||||
namespaces that tc-lib-pdf emits automatically. Inspect the XMP stream with
|
||||
a PDF inspector or <code>exiftool -XMP -b output.pdf</code> to verify.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">Block 1 — IPTC Core rights</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Namespace: <b>Iptc4xmpCore</b> (http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/)<br />
|
||||
Injection key: <code>x:xmpmeta.rdf:RDF</code><br />
|
||||
Contains: CopyrightNotice, CreatorContactInfo (email, URL), UsageTerms.<br />
|
||||
Typical use: photojournalism DAM, stock-photography catalogues.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">Block 2 — XMP-MM version history</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Namespace: <b>xmpMM</b> (http://ns.adobe.com/xap/1.0/mm/)<br />
|
||||
Injection key: <code>x:xmpmeta.rdf:RDF</code><br />
|
||||
Contains: DocumentID, InstanceID, VersionID, History (sequence of events), DerivedFrom.<br />
|
||||
Typical use: document management systems, digital asset lineage tracking.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">Block 3 — Custom application metadata</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Namespace: <b>tcpdf</b> (https://github.com/tecnickcom/tc-lib-pdf/ns/xmp/1.0/)<br />
|
||||
Injection key: <code>x:xmpmeta.rdf:RDF</code><br />
|
||||
Contains: exampleId, generatedBy, generationDate, featureTag.<br />
|
||||
Typical use: integration metadata for build pipelines, print-MIS systems, or
|
||||
any workflow that needs to carry arbitrary key-value pairs inside the PDF
|
||||
without modifying the Info dictionary.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">Important notes</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
• The injected XML is embedded as-is; the library does NOT validate XMP well-formedness.<br />
|
||||
• Multiple calls with the same key are concatenated in insertion order.<br />
|
||||
• Injection into <code>x:xmpmeta.rdf:RDF.rdf:Description</code> adds properties to the
|
||||
shared Description block; prefer a standalone Description block (as done here) to
|
||||
keep namespace declarations self-contained.<br />
|
||||
• All standard metadata (title, author, subject, keywords, dates, producer) is still
|
||||
emitted automatically and is not affected by setCustomXMP().
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E061_user_rights_reader_extensions.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
// NOTE: This example requires a signing certificate. Run the following to create a self-signed one:
|
||||
// cd examples/data/cert
|
||||
// openssl req -x509 -nodes -days 365000 -newkey rsa:2048 -keyout tcpdf.crt -out tcpdf.crt \
|
||||
// -subj "/CN=tc-lib-pdf demo"
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate Adobe Reader extension rights via setUserRights().
|
||||
*
|
||||
* Background
|
||||
* ──────────
|
||||
* Standard PDF encryption (setEncrypt / E045) controls which operations a
|
||||
* user is *prevented* from performing. That is a restriction model.
|
||||
*
|
||||
* Reader Extensions (UR — Usage Rights) are a complementary *enablement*
|
||||
* model: they grant additional privileges to free Adobe Reader users that
|
||||
* Reader would otherwise reserve for Acrobat Pro. Common examples:
|
||||
* • Filling in forms and saving the filled data
|
||||
* • Creating, modifying, and deleting annotations (comments, stamps, etc.)
|
||||
* • Signing existing signature fields
|
||||
* • Exporting embedded files
|
||||
*
|
||||
* Implementation
|
||||
* ──────────────
|
||||
* UR rights are embedded via a special /UR3 signature object (SubFilter:
|
||||
* adbe.pkcs7.detached with cert_type = 0, i.e. no DocMDP constraint).
|
||||
* This is distinct from a CMS approval or certification signature:
|
||||
* • cert_type > 0 → DocMDP (document modification detection / certification)
|
||||
* • cert_type = 0 → UR (usage-rights extension)
|
||||
*
|
||||
* setUserRights() accepts an array of right categories:
|
||||
* enabled (bool) must be true to activate UR output
|
||||
* document (string) document-level rights e.g. '/FullSave'
|
||||
* form (string) form-filling rights e.g. '/FillIn /Export'
|
||||
* formex (string) form extras e.g. '/BarcodePlaintext'
|
||||
* annots (string) annotation rights e.g. '/Create /Delete /Modify /Copy /Import /Export'
|
||||
* signature (string) signing rights e.g. '/Modify'
|
||||
* ef (string) embedded-file rights e.g. '/Create /Delete /Modify /Import'
|
||||
*
|
||||
* The companion setSignature() call wires the UR3 signature using the
|
||||
* supplied certificate. cert_type = 0 selects the UR branch in the output
|
||||
* layer (see Output::getOutSignatureUserRights).
|
||||
*
|
||||
* IMPORTANT: UR rights are only honoured by Adobe Reader / Acrobat. Most
|
||||
* open-source readers do not enforce or display UR distinctions.
|
||||
*/
|
||||
|
||||
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
|
||||
if ($certPath === false) {
|
||||
throw new \RuntimeException(
|
||||
'Missing signing certificate: examples/data/cert/tcpdf.crt'
|
||||
. "\n"
|
||||
. 'Create it with:'
|
||||
. "\n"
|
||||
. ' openssl req -x509 -nodes -days 365000 -newkey rsa:2048 \\'
|
||||
. "\n"
|
||||
. ' -keyout examples/data/cert/tcpdf.crt -out examples/data/cert/tcpdf.crt \\'
|
||||
. "\n"
|
||||
. ' -subj "/CN=tc-lib-pdf demo"',
|
||||
);
|
||||
}
|
||||
|
||||
$cert = 'file://' . $certPath;
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 061');
|
||||
$pdf->setTitle('Reader Extension Rights (UR Signature)');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example user rights reader extensions UR signature form annotation');
|
||||
$pdf->setPDFFilename('E061_user_rights_reader_extensions.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Enable Reader Extension Rights
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Grant form-filling, commenting, and signing rights to free Adobe Reader.
|
||||
$pdf->setUserRights([
|
||||
'enabled' => true,
|
||||
'document' => '/FullSave',
|
||||
'form' => '/FillIn /Export',
|
||||
'annots' => '/Create /Delete /Modify /Copy /Import /Export',
|
||||
'signature' => '/Modify',
|
||||
'ef' => '/Create /Delete /Modify /Import',
|
||||
]);
|
||||
|
||||
// Wire the UR3 signature (cert_type = 0 → UR path, not DocMDP).
|
||||
$pdf->setSignature([
|
||||
'cert_type' => 0, // 0 = UR, not DocMDP certification
|
||||
'password' => '',
|
||||
'privkey' => $cert,
|
||||
'signcert' => $cert,
|
||||
'info' => [
|
||||
'Name' => 'tc-lib-pdf',
|
||||
'Location' => 'Demo',
|
||||
'Reason' => 'Enabling Reader Extension Rights',
|
||||
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
],
|
||||
]);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Add a simple interactive text field to exercise form-filling rights
|
||||
// -----------------------------------------------------------------------
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
|
||||
$page1 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
// Re-insert non-bold base font so the font stack is in a clean state
|
||||
// before addHTMLCell starts its height-estimation pass.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
// Info block
|
||||
$html = <<<'HTML'
|
||||
<h1 style="font-size:16pt; color:#003366;">Reader Extension Rights (UR Signature)</h1>
|
||||
<p style="font-size:10pt; color:#333333;">
|
||||
This PDF uses a /UR3 usage-rights signature to grant additional privileges to
|
||||
free Adobe Reader users beyond the default read-only experience.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">Rights enabled in this document</h2>
|
||||
<table border="0" cellpadding="3">
|
||||
<tr><td style="font-size:9pt; color:#003366; font-weight:bold; width:90mm;">Category</td>
|
||||
<td style="font-size:9pt; color:#003366; font-weight:bold;">Granted rights</td></tr>
|
||||
<tr><td style="font-size:9pt;">Document</td>
|
||||
<td style="font-size:9pt;">/FullSave — Reader may save a filled-in copy</td></tr>
|
||||
<tr><td style="font-size:9pt;">Form</td>
|
||||
<td style="font-size:9pt;">/FillIn /Export — fill fields and export data</td></tr>
|
||||
<tr><td style="font-size:9pt;">Annotations</td>
|
||||
<td style="font-size:9pt;">/Create /Delete /Modify /Copy /Import /Export</td></tr>
|
||||
<tr><td style="font-size:9pt;">Signature</td>
|
||||
<td style="font-size:9pt;">/Modify — apply or clear a digital signature</td></tr>
|
||||
<tr><td style="font-size:9pt;">Embedded files</td>
|
||||
<td style="font-size:9pt;">/Create /Delete /Modify /Import</td></tr>
|
||||
</table>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">Interactive field (test form-fill right)</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
The text field below can be filled and <b>saved</b> in free Adobe Reader because
|
||||
the FullSave document right has been enabled. Without UR rights, Reader would
|
||||
only allow printing a filled-in copy, not saving it.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
// Add a text field that exercises the form-filling right.
|
||||
$ffid = $pdf->addFFText('ur_test_field', 15, 140, 120, 8, ['value' => 'Type here and save...']);
|
||||
$pdf->page->addAnnotRef($ffid);
|
||||
|
||||
// Label for the field.
|
||||
// Re-insert non-bold font before getTextCell to keep the font stack clean.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Saveable text field:',
|
||||
15.0,
|
||||
133.0,
|
||||
60.0,
|
||||
6.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 2 — Contrast with DocMDP certification (cert_type > 0)
|
||||
// -----------------------------------------------------------------------
|
||||
$page2 = $pdf->addPage();
|
||||
// Re-insert non-bold base font before addHTMLCell.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$html2 = <<<'HTML'
|
||||
<h1 style="font-size:16pt; color:#003366;">UR vs DocMDP — Key Differences</h1>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">cert_type = 0 → Usage Rights (UR3) — this document</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Purpose: <b>grant</b> extra privileges to Reader.<br />
|
||||
Signature type: /UR3 — not a DocMDP certification.<br />
|
||||
Does not constrain future modifications.<br />
|
||||
Reader shows a "Reader Extensions" badge rather than a certification badge.<br />
|
||||
Created via: <code>setUserRights([...]) + setSignature(['cert_type' => 0, ...])</code>
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">cert_type = 1/2/3 → DocMDP Certification</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Purpose: <b>certify</b> authorship and <b>restrict</b> allowed changes.<br />
|
||||
cert_type 1 = no changes allowed; 2 = form-filling + signing; 3 = + annotations.<br />
|
||||
Reader shows a certification badge; further changes break the signature seal.<br />
|
||||
Created via: <code>setSignature(['cert_type' => 2, ...])</code> (see E007–E009)
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:13pt; color:#005599;">Standard encryption (E045) vs UR rights</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Standard PDF encryption sets a <b>permission bitmap</b> that <b>prevents</b> operations
|
||||
(printing, copying, modifying) unless the owner password is supplied.<br />
|
||||
UR rights are orthogonal: they <b>enable</b> specific Reader features that are
|
||||
otherwise locked regardless of password protection. Both mechanisms can be
|
||||
combined in the same document.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html2, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E062_bidi_mixed_rtl_ltr.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// Unifont covers ~65 000 Unicode glyphs (including per-glyph cbbox data).
|
||||
// Loading its full metric array exceeds the 128 MB PHP default.
|
||||
\ini_set('memory_limit', '256M');
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate mixed bidirectional (BiDi) text layout using setRTL().
|
||||
*
|
||||
* tc-lib-pdf supports Unicode BiDi text via tc-lib-unicode. The document
|
||||
* direction is set with setRTL(bool):
|
||||
*
|
||||
* setRTL(false) — LTR default (Latin, CJK, etc.)
|
||||
* setRTL(true) — RTL default (Arabic, Hebrew, Persian, Urdu, etc.)
|
||||
*
|
||||
* The direction affects:
|
||||
* • Cell and text origin anchoring (LTR: x is left edge; RTL: x is right edge)
|
||||
* • HTML block-level alignment defaults (text-align)
|
||||
* • Cursor advancement direction
|
||||
*
|
||||
* Within an HTML block the Unicode BiDi algorithm handles inline direction
|
||||
* switches automatically for mixed runs (e.g. Hebrew words embedded inside
|
||||
* an English sentence or vice-versa).
|
||||
*
|
||||
* Difference from E003 (pure Arabic/Persian):
|
||||
* E003 uses a pure RTL document with no LTR direction switching.
|
||||
* This example focuses on the MID-DOCUMENT switch between RTL and LTR pages
|
||||
* and on truly mixed paragraphs that contain both Hebrew and Latin text
|
||||
* on the same line, which is common in real-world bilingual publishing.
|
||||
*
|
||||
* Font note: Unifont contains glyphs for virtually all Unicode scripts and
|
||||
* correctly supports BiDi rendering, making it the safest choice for
|
||||
* multilingual examples.
|
||||
*/
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 062');
|
||||
$pdf->setTitle('Mixed BiDi RTL/LTR Typography');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example bidi rtl ltr hebrew arabic latin mixed direction');
|
||||
$pdf->setPDFFilename('E062_bidi_mixed_rtl_ltr.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent(false);
|
||||
|
||||
// Unifont — comprehensive Unicode coverage including Hebrew
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'unifont', '', 12);
|
||||
|
||||
// ===================================================================
|
||||
// Page 1 — LTR document with embedded RTL runs
|
||||
// ===================================================================
|
||||
$pdf->setRTL(false); // default: LTR
|
||||
$page1 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$html1 = <<<'HTML'
|
||||
<h1 style="font-size:15pt; color:#003366;">Page 1 — LTR document, embedded RTL runs</h1>
|
||||
|
||||
<p style="font-size:10pt; color:#333333;">
|
||||
This paragraph is in English (LTR). Hebrew words are embedded inline and the
|
||||
Unicode BiDi algorithm resolves their direction automatically without any
|
||||
explicit markup. For example: the Hebrew word for "peace" is שָׁלוֹם and the
|
||||
word for "hello" is שָׁלוֹם (shalom). The sentence continues in English after
|
||||
each Hebrew run.
|
||||
</p>
|
||||
|
||||
<p style="font-size:10pt; color:#333333;">
|
||||
A mixed technical phrase: the algorithm (אַלְגּוֹרִיתְם) runs in
|
||||
O(n log n) time. The constant (קְבוּעַ) is defined as 3.14.
|
||||
Numbers like 1, 2, 3 remain LTR regardless of surrounding script context.
|
||||
</p>
|
||||
|
||||
<p style="font-size:10pt; color:#333333;">
|
||||
Quotation from the Hebrew Bible (Psalm 133:1, LTR paragraph):
|
||||
<span style="color:#660000;">הִנֵּה מַה טוֹב וּמַה נָּעִים שֶׁבֶת אַחִים גַּם יָחַד</span>
|
||||
— "How good and pleasant it is when brothers dwell together in unity."
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:12pt; color:#005599;">Right-aligned Hebrew block (LTR document, explicit alignment)</h2>
|
||||
<p style="font-size:10pt; text-align:right; color:#333333;">
|
||||
בְּרֵאשִׁית בָּרָא אֱלֹהִים אֵת הַשָּׁמַיִם וְאֵת הָאָרֶץ<br />
|
||||
וְהָאָרֶץ הָיְתָה תֹהוּ וָבֹהוּ וְחֹשֶׁךְ עַל פְּנֵי תְהוֹם<br />
|
||||
וְרוּחַ אֱלֹהִים מְרַחֶפֶת עַל פְּנֵי הַמָּיִם
|
||||
</p>
|
||||
<p style="font-size:8pt; color:#666666; text-align:right;">Genesis 1:1-2 (Hebrew)</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html1, posx: 10, posy: 10, width: 190);
|
||||
|
||||
// ===================================================================
|
||||
// Page 2 — RTL document with embedded LTR runs
|
||||
// ===================================================================
|
||||
$pdf->setRTL(true); // switch to RTL for this page
|
||||
$page2 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$html2 = <<<'HTML'
|
||||
<h1 style="font-size:15pt; color:#003366;">עמוד 2 — מסמך RTL עם רצפי LTR</h1>
|
||||
|
||||
<p style="font-size:10pt; color:#333333; text-align:right;">
|
||||
פסקה זו נכתבת בעברית (RTL). מונחים אנגליים כגון <span dir="ltr">Unicode BiDi</span>
|
||||
ו-<span dir="ltr">tc-lib-pdf</span> מוטמעים בשורה, ואלגוריתם ה-BiDi מטפל בכיוונם
|
||||
אוטומטית. המשפט ממשיך בעברית לאחר כל רצף אנגלי.
|
||||
</p>
|
||||
|
||||
<p style="font-size:10pt; color:#333333; text-align:right;">
|
||||
ניתן לשלב מספרים כגון 42, 3.14 ו-100% בתוך טקסט עברי ללא
|
||||
סימון מיוחד. הם מוצגים בסדר קריאה נכון בהקשרם.
|
||||
</p>
|
||||
|
||||
<p style="font-size:10pt; color:#333333; text-align:right;">
|
||||
משפט טכני מעורב: הפונקציה
|
||||
<span dir="ltr" style="color:#0000aa; font-weight:bold;">setRTL(true)</span>
|
||||
מגדירה את כיוון מסמך ברירת המחדל ל-RTL. ניתן להחליף כיוון
|
||||
בכל עמוד על ידי קריאה ל-<span dir="ltr" style="color:#0000aa;">setRTL(false)</span>
|
||||
לפני <span dir="ltr" style="color:#0000aa;">addPage()</span>.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html2, posx: 10, posy: 10, width: 190);
|
||||
|
||||
// ===================================================================
|
||||
// Page 3 — Back to LTR: summary and guidance
|
||||
// ===================================================================
|
||||
$pdf->setRTL(false); // back to LTR
|
||||
$page3 = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$html3 = <<<'HTML'
|
||||
<h1 style="font-size:15pt; color:#003366;">Page 3 — Summary and Guidance</h1>
|
||||
|
||||
<h2 style="font-size:12pt; color:#005599;">setRTL() scope</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
<code>setRTL()</code> sets the default document direction. Call it <b>before</b>
|
||||
<code>addPage()</code> to apply the direction to the new page context. Changing
|
||||
direction mid-page is possible but affects all subsequent cell-placement calls on
|
||||
that page.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:12pt; color:#005599;">Inline BiDi — no markup needed</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
The Unicode BiDi algorithm (UAX #9) handles inline direction switches
|
||||
automatically. You do not need explicit <code>dir="rtl"</code> or
|
||||
<code>dir="ltr"</code> attributes for most runs — the script category of each
|
||||
character determines its display direction. Use explicit <code>dir</code>
|
||||
only when the context-based algorithm would resolve the direction incorrectly
|
||||
(e.g. punctuation adjacent to a direction boundary).
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:12pt; color:#005599;">Font coverage</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
This example uses <b>Unifont</b>, which covers virtually all Unicode blocks
|
||||
including Hebrew, Arabic, Devanagari, CJK, and Latin. For production use,
|
||||
consider a font with better kerning and glyph quality for your primary script
|
||||
(DejaVu Sans for Latin+Hebrew, Noto fonts for full multilingual coverage).
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:12pt; color:#005599;">Pure RTL scripts — see also</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
For documents that are entirely in Arabic or Persian (no mixed LTR content)
|
||||
see <b>E003_persian_arabic.php</b>, which demonstrates <code>setRTL(false)</code>
|
||||
(the document is LTR but the HTML content uses <code>text-align:right</code>
|
||||
combined with Unicode RTL codepoints).
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html3, posx: 10, posy: 10, width: 190);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,842 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E063_manual_tag_tree.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate manual PDF/UA structure-element tagging via
|
||||
* beginStructElem() / endStructElem().
|
||||
*
|
||||
* Background
|
||||
* ──────────
|
||||
* Accessible (tagged) PDFs carry a logical structure tree that screen readers
|
||||
* use to navigate and read content in reading order. When tc-lib-pdf operates
|
||||
* in a pdfua or pdfua1/pdfua2 mode it auto-tags content produced by
|
||||
* addHTMLCell() using the HTML semantic elements (h1→H1, p→P, etc.).
|
||||
*
|
||||
* For content produced with the lower-level text APIs — or for cases
|
||||
* where you need precise control over structure roles — you can bracket each
|
||||
* logical block with:
|
||||
*
|
||||
* beginStructElem(string $role, int $pid)
|
||||
* Opens a structure-element bracket. All tagged content produced
|
||||
* until the matching endStructElem() is associated with this element.
|
||||
* $role is a PDF structure role (see PDF 32000 §14.8):
|
||||
* Headings : H, H1 … H6
|
||||
* Body : P, Blockquote, Note, Caption
|
||||
* List : L, LI, Lbl, LBody
|
||||
* Table : Table, TR, TH, TD
|
||||
* Inline : Span, Link, Reference, BibEntry
|
||||
* Other : Document, Part, Sect, Art, Figure, TOC, TOCI
|
||||
* $pid is the page ID from addPage()['pid'].
|
||||
*
|
||||
* endStructElem()
|
||||
* Closes the current bracket. The completed element (with all its
|
||||
* tagged content MCIDs) is appended to the structure log.
|
||||
* Empty elements (no tagged content inside the bracket) are silently
|
||||
* discarded.
|
||||
*
|
||||
* When pdfuaMode is '' (plain PDF mode) both methods are no-ops, so the
|
||||
* same code runs safely in plain and PDF/UA modes without changes.
|
||||
*
|
||||
* NOTE: beginStructElem()/endStructElem() only associate MCIDs with content
|
||||
* emitted through the tagged text path. For manual tagging, use addTextCell()
|
||||
* (second argument is the page ID) rather than writing raw getTextCell()
|
||||
* output directly with page->addContent().
|
||||
*
|
||||
* This example uses 'pdfua1' mode and demonstrates the full manual-tagging
|
||||
* surface across four pages:
|
||||
*
|
||||
* Page 1 — Heading roles (H1, H2, H3), P, Figure, Caption
|
||||
* Page 2 — Note, Blockquote, multi-paragraph body
|
||||
* Page 3 — Sect/Art grouping containers; list structure (L > LI > Lbl + LBody)
|
||||
* Page 4 — Table nesting (Table > TR > TH / TD); Figure with /Alt alternate text
|
||||
*
|
||||
* Non-semantic decorative content can be emitted as Artifact marked-content
|
||||
* with addArtifactContent() or, at the low level, by writing the strings
|
||||
* returned by beginArtifact() / endArtifact() with page->addContent().
|
||||
* This example uses addArtifactContent() to add decorative separator rules as
|
||||
* /Artifact with /Type /Layout.
|
||||
*
|
||||
* All content is tagged with addTextCell() inside explicit struct-elem brackets.
|
||||
* Compare with E015–E017 which enable pdfua mode via addHTMLCell (auto-tagged).
|
||||
*/
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::Pdfua1,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 063');
|
||||
$pdf->setTitle('Manual Tag Tree (PDF/UA Structure Elements)');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example pdfua tagged structure accessibility wcag screen reader');
|
||||
$pdf->setPDFFilename('E063_manual_tag_tree.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$leftMargin = 15.0;
|
||||
$rightMargin = 15.0;
|
||||
$pdf->setDefaultCellMargin(top: 0.0, right: $rightMargin, bottom: 0.0, left: 0.0);
|
||||
|
||||
$setFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, string $family, string $style, int $size): array {
|
||||
if ($family === 'helvetica') {
|
||||
$family = 'dejavusans';
|
||||
}
|
||||
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size);
|
||||
$pdf->page->addContent($font['out']);
|
||||
return $font;
|
||||
};
|
||||
|
||||
$addDecorativeSeparator = static function (\Com\Tecnick\Pdf\Tcpdf $pdf, int $pid, float $posY) use ($leftMargin): void {
|
||||
$lineStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.25,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#bdbdbd',
|
||||
'fillColor' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$pdf->addArtifactContent($pdf->graph->getLine($leftMargin, $posY, 195.0, $posY, $lineStyle), $pid, 'Layout');
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Font setup — insert before addPage()
|
||||
// -----------------------------------------------------------------------
|
||||
$pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 1 — H1, H2, H3, P, Caption, Figure structure elements
|
||||
// -----------------------------------------------------------------------
|
||||
$page1 = $pdf->addPage();
|
||||
$pid1 = $page1['pid'];
|
||||
$addDecorativeSeparator($pdf, $pid1, 16.0);
|
||||
|
||||
// --- H1 heading ---
|
||||
$setFont($pdf, 'helvetica', 'B', 16);
|
||||
|
||||
$pdf->beginStructElem(role: 'H1', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
'Manual Tag Tree — PDF/UA Structure Elements',
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
20.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// --- Introductory paragraph (P) ---
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$intro =
|
||||
'This document uses beginStructElem() and endStructElem() to build '
|
||||
. 'the accessibility structure tree manually. Every piece of text is '
|
||||
. 'wrapped in an explicit structure-element bracket that maps content '
|
||||
. 'to a PDF logical role (H1, H2, H3, P, Caption). A screen reader can '
|
||||
. 'navigate the heading hierarchy and read body paragraphs in the correct '
|
||||
. 'logical order.';
|
||||
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
$intro,
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
32.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// --- Section 1: H2 + P ---
|
||||
$setFont($pdf, 'helvetica', 'B', 14);
|
||||
|
||||
$pdf->beginStructElem(role: 'H2', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
'Section 1 — Heading Roles',
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
55.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$sec1body =
|
||||
'Structure roles H1 through H6 define the heading hierarchy. '
|
||||
. 'H1 is the document title; H2 is a top-level section heading; H3 is a '
|
||||
. 'sub-section; and so on. Screen readers present this outline as a '
|
||||
. 'navigable table of contents. Nesting is implied by the sequence of '
|
||||
. 'structure elements logged by endStructElem().';
|
||||
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
$sec1body,
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
64.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// --- Sub-section: H3 ---
|
||||
$setFont($pdf, 'helvetica', 'BI', 11);
|
||||
|
||||
$pdf->beginStructElem(role: 'H3', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
'1.1 — Sub-section with H3 role',
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
85.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
'An H3 element is used here to show a third level in the outline. '
|
||||
. 'The structure tree will contain: H1 > H2 > H3 > P, reflecting the '
|
||||
. 'logical reading order of this page.',
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
93.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// --- Section 2: H2 + P + Figure + Caption ---
|
||||
$setFont($pdf, 'helvetica', 'B', 14);
|
||||
|
||||
$pdf->beginStructElem(role: 'H2', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
'Section 2 — Figure and Caption Roles',
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
113.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
'The Figure role wraps graphical content. '
|
||||
. 'A Caption role immediately following a Figure provides an '
|
||||
. 'accessible description of the visual element for screen-reader users.',
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
122.0,
|
||||
150,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// Draw and tag a simple coloured rectangle as Figure content.
|
||||
$figStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#336699',
|
||||
'fillColor' => '#cce0ff',
|
||||
],
|
||||
];
|
||||
// The bounding box is required by PDF/UA for figures contained on a single page.
|
||||
// It is expressed in points, from the bottom-left page corner.
|
||||
$pdf->addTaggedFigureContent(
|
||||
$pdf->graph->getStartTransform() . $pdf->graph->getRect($leftMargin, 143.0, 180.0, 25.0, 'DF', $figStyle)
|
||||
. $pdf->graph->getStopTransform(),
|
||||
$pid1,
|
||||
'Blue placeholder rectangle representing a figure area',
|
||||
[
|
||||
$pdf->toPoints($leftMargin),
|
||||
$pdf->toPoints($page1['height'] - 143.0 - 25.0),
|
||||
$pdf->toPoints($leftMargin + 180.0),
|
||||
$pdf->toPoints($page1['height'] - 143.0),
|
||||
],
|
||||
);
|
||||
|
||||
// Caption for the figure.
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black'), $pid1);
|
||||
$setFont($pdf, 'helvetica', 'I', 8);
|
||||
|
||||
$pdf->beginStructElem(role: 'Caption', pid: $pid1);
|
||||
$pdf->addTextCell(
|
||||
'Figure 1 — Placeholder rectangle representing graphical content (Caption role)',
|
||||
$pid1,
|
||||
$leftMargin,
|
||||
170.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 2 — Note, Blockquote, and multi-paragraph body
|
||||
// -----------------------------------------------------------------------
|
||||
$page2 = $pdf->addPage();
|
||||
$pid2 = $page2['pid'];
|
||||
$addDecorativeSeparator($pdf, $pid2, 16.0);
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 14);
|
||||
|
||||
$pdf->beginStructElem(role: 'H2', pid: $pid2);
|
||||
$pdf->addTextCell(
|
||||
'Page 2 — Note, Blockquote, and Multi-element Brackets',
|
||||
$pid2,
|
||||
$leftMargin,
|
||||
20.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
// Note element (with explicit ID for validator compatibility)
|
||||
$pdf->beginStructElem(role: 'Note', pid: $pid2, alt: null, attr: ['ID' => 'note-p2-01']);
|
||||
$pdf->addTextCell(
|
||||
'NOTE: beginStructElem() / endStructElem() are no-ops in plain PDF mode '
|
||||
. '(pdfuaMode = ""). The same code runs safely in both plain and PDF/UA '
|
||||
. 'modes without conditional branching.',
|
||||
$pid2,
|
||||
$leftMargin,
|
||||
32.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// Blockquote element
|
||||
$setFont($pdf, 'helvetica', 'BI', 11);
|
||||
|
||||
$pdf->beginStructElem(role: 'BlockQuote', pid: $pid2);
|
||||
$pdf->addTextCell(
|
||||
'"Tagged PDF is the foundation of accessible PDF. '
|
||||
. 'Without a well-formed structure tree, automated tools and assistive '
|
||||
. 'technologies cannot reliably interpret document content."',
|
||||
$pid2,
|
||||
$leftMargin,
|
||||
52.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', 'I', 8);
|
||||
|
||||
$pdf->beginStructElem(role: 'Caption', pid: $pid2);
|
||||
$pdf->addTextCell(
|
||||
'— ISO 14289-1:2012 (PDF/UA-1) rationale',
|
||||
$pid2,
|
||||
$leftMargin,
|
||||
72.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// Multi-paragraph body section
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$paras = [
|
||||
'Each call to endStructElem() closes the innermost open bracket. '
|
||||
. 'Completed elements keep their nested parent-child relationships, so '
|
||||
. 'the emitted structure tree follows the bracket hierarchy and preserves '
|
||||
. 'the reading order of nested content blocks.',
|
||||
|
||||
'A structure bracket that receives no tagged content (i.e. no addTextCell '
|
||||
. 'call between beginStructElem and endStructElem) is silently discarded. '
|
||||
. 'This prevents empty structure nodes from appearing in the tree.',
|
||||
|
||||
'Pages 3 and 4 of this document demonstrate the remaining role categories: '
|
||||
. 'grouping containers (Sect, Art), list structure (L, LI, Lbl, LBody), '
|
||||
. 'and table structure (Table, TR, TH, TD) — each requiring multi-level '
|
||||
. 'nested brackets that the library resolves at getOutPDFString() time.',
|
||||
];
|
||||
|
||||
$yPos = 85.0;
|
||||
foreach ($paras as $para) {
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid2);
|
||||
$pdf->addTextCell(
|
||||
$para,
|
||||
$pid2,
|
||||
$leftMargin,
|
||||
$yPos,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
$yPos += 25.0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 3 — Sect/Art grouping containers + List structure
|
||||
// -----------------------------------------------------------------------
|
||||
$page3 = $pdf->addPage();
|
||||
$pid3 = $page3['pid'];
|
||||
$addDecorativeSeparator($pdf, $pid3, 16.0);
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 16);
|
||||
|
||||
$pdf->beginStructElem(role: 'H2', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'Page 3 — Grouping Containers and List Structure',
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
20.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// ── Sect wrapping a sub-section (H3 + P inside a Sect container) ──────
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
|
||||
$pdf->beginStructElem(role: 'Sect', pid: $pid3);
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 13);
|
||||
$pdf->beginStructElem(role: 'H3', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'3.1 — Sect Container',
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
34.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'The Sect (Section) role is a grouping container: it contributes no '
|
||||
. 'content of its own but wraps related blocks — here an H3 and this P '
|
||||
. 'paragraph — into a single logical section node in the structure tree. '
|
||||
. 'Screen readers and PDF validators see the H3 + P as children of the Sect.',
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
43.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$pdf->endStructElem(); // Sect
|
||||
|
||||
// ── Art container ─────────────────────────────────────────────────────
|
||||
$pdf->beginStructElem(role: 'Art', pid: $pid3);
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 13);
|
||||
$pdf->beginStructElem(role: 'H3', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'3.2 — Art Container',
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
65.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'The Art (Article) role marks a self-contained composition: its content '
|
||||
. 'could stand alone as a discrete piece. It is distinguished from Sect '
|
||||
. 'in that Sect groups thematically related material within a larger work, '
|
||||
. 'while Art denotes an independently distributable unit.',
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
74.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$pdf->endStructElem(); // Art
|
||||
|
||||
// ── List: L > LI > {Lbl + LBody} ─────────────────────────────────────
|
||||
$setFont($pdf, 'helvetica', 'B', 13);
|
||||
$pdf->beginStructElem(role: 'H3', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'3.3 — List Structure (L > LI > Lbl + LBody)',
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
97.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'Each list item (LI) contains a label (Lbl) and a body (LBody). '
|
||||
. 'The outer L bracket wraps all items into one logical list node.',
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
107.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$listItems = [
|
||||
['Headings (H1–H6)', 'Define the document outline navigated by screen readers.'],
|
||||
['Body roles (P, Note, Blockquote)', 'Carry prose content at the block level.'],
|
||||
['Grouping roles (Sect, Art, Part)', 'Wrap related blocks without adding visible content.'],
|
||||
['List roles (L, LI, Lbl, LBody)', 'Express enumerated or bulleted list structure.'],
|
||||
['Table roles (Table, TR, TH, TD)', 'Capture row/column relationships in data tables.'],
|
||||
];
|
||||
|
||||
$pdf->beginStructElem(role: 'L', pid: $pid3);
|
||||
|
||||
$itemY = 122.0;
|
||||
foreach ($listItems as [$label, $body]) {
|
||||
$pdf->beginStructElem(role: 'LI', pid: $pid3);
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 10);
|
||||
$pdf->beginStructElem(role: 'Lbl', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
'• ' . $label,
|
||||
$pid3,
|
||||
$leftMargin,
|
||||
$itemY,
|
||||
65.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem(); // Lbl
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->beginStructElem(role: 'LBody', pid: $pid3);
|
||||
$pdf->addTextCell(
|
||||
$body,
|
||||
$pid3,
|
||||
$leftMargin + 65.0,
|
||||
$itemY,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem(); // LBody
|
||||
|
||||
$pdf->endStructElem(); // LI
|
||||
$itemY += 8.0;
|
||||
}
|
||||
|
||||
$pdf->endStructElem(); // L
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 4 — Table nesting + Figure with /Alt alternate description
|
||||
// -----------------------------------------------------------------------
|
||||
$page4 = $pdf->addPage();
|
||||
$pid4 = $page4['pid'];
|
||||
$addDecorativeSeparator($pdf, $pid4, 16.0);
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 16);
|
||||
$pdf->beginStructElem(role: 'H2', pid: $pid4);
|
||||
$pdf->addTextCell(
|
||||
'Page 4 — Table Structure and Figure with Alt-Text',
|
||||
$pid4,
|
||||
$leftMargin,
|
||||
20.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// ── Table ─────────────────────────────────────────────────────────────
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid4);
|
||||
$pdf->addTextCell(
|
||||
'The Table role wraps a complete data table. Each row is a TR; header '
|
||||
. 'cells are TH; data cells are TD. All brackets must be closed '
|
||||
. 'inside-out before moving to the next row.',
|
||||
$pid4,
|
||||
$leftMargin,
|
||||
32.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
// Column geometry (three columns)
|
||||
$colX = [$leftMargin, $leftMargin + 55.0, $leftMargin + 120.0];
|
||||
$colW = [55.0, 65.0, 60.0];
|
||||
$rowH = 8.0;
|
||||
$tableY = 52.0;
|
||||
|
||||
$tableHeaders = ['Structure Role', 'Category', 'Nesting context'];
|
||||
$tableHeaderIds = ['th-role', 'th-category', 'th-context'];
|
||||
$tableRows = [
|
||||
['H1–H6', 'Heading', 'Document / Sect / Art'],
|
||||
['P', 'Body', 'Document / Sect / Art'],
|
||||
['Note, Blockquote', 'Body', 'Document / Sect / Art'],
|
||||
['L', 'List', 'Document / Sect'],
|
||||
['LI', 'List item', 'Inside L'],
|
||||
['Lbl / LBody', 'List parts', 'Inside LI'],
|
||||
['Table', 'Table', 'Document / Sect'],
|
||||
['TR', 'Table row', 'Inside Table'],
|
||||
['TH / TD', 'Table cell', 'Inside TR'],
|
||||
['Sect / Art / Part', 'Container', 'Document-level'],
|
||||
['Figure', 'Graphic', 'Document / Sect'],
|
||||
['Caption', 'Caption', 'After Figure'],
|
||||
];
|
||||
|
||||
$pdf->beginStructElem(role: 'Table', pid: $pid4);
|
||||
|
||||
// Header row
|
||||
$pdf->beginStructElem(role: 'TR', pid: $pid4);
|
||||
foreach ($tableHeaders as $idx => $hdr) {
|
||||
$setFont($pdf, 'helvetica', 'B', 9);
|
||||
$pdf->beginStructElem(role: 'TH', pid: $pid4, alt: null, attr: [
|
||||
'O' => 'Table',
|
||||
'ID' => $tableHeaderIds[$idx],
|
||||
'Scope' => 'Column',
|
||||
]);
|
||||
$pdf->addTextCell(
|
||||
$hdr,
|
||||
$pid4,
|
||||
$colX[$idx],
|
||||
$tableY,
|
||||
$colW[$idx],
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem(); // TH
|
||||
}
|
||||
$pdf->endStructElem(); // TR (header)
|
||||
|
||||
// Data rows
|
||||
foreach ($tableRows as $row) {
|
||||
$tableY += $rowH;
|
||||
$pdf->beginStructElem(role: 'TR', pid: $pid4);
|
||||
foreach ($row as $idx => $cell) {
|
||||
$setFont($pdf, 'helvetica', '', 9);
|
||||
$pdf->beginStructElem(role: 'TD', pid: $pid4, alt: null, attr: [
|
||||
'O' => 'Table',
|
||||
'Headers' => $tableHeaderIds[$idx],
|
||||
]);
|
||||
$pdf->addTextCell(
|
||||
$cell,
|
||||
$pid4,
|
||||
$colX[$idx],
|
||||
$tableY,
|
||||
$colW[$idx],
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem(); // TD
|
||||
}
|
||||
$pdf->endStructElem(); // TR
|
||||
}
|
||||
|
||||
$pdf->endStructElem(); // Table
|
||||
|
||||
// ── Figure with /Alt alternate description ────────────────────────────
|
||||
$figY = $tableY + 18.0;
|
||||
|
||||
$setFont($pdf, 'helvetica', 'B', 13);
|
||||
$pdf->beginStructElem(role: 'H3', pid: $pid4);
|
||||
$pdf->addTextCell(
|
||||
'4.1 — Figure with /Alt Entry',
|
||||
$pid4,
|
||||
$leftMargin,
|
||||
$figY,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$figY += 10.0;
|
||||
|
||||
$setFont($pdf, 'helvetica', '', 10);
|
||||
$pdf->beginStructElem(role: 'P', pid: $pid4);
|
||||
$pdf->addTextCell(
|
||||
'For non-text graphics, use addTaggedFigureContent() and pass an /Alt '
|
||||
. 'description for accessibility. The string is written into the Figure '
|
||||
. 'structure-element dictionary and read aloud by screen readers when '
|
||||
. 'the graphical content cannot be represented as plain text.',
|
||||
$pid4,
|
||||
$leftMargin,
|
||||
$figY,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$figY += 22.0;
|
||||
|
||||
// Draw a simple placeholder rectangle for the figure.
|
||||
$figStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#4a7c59',
|
||||
'fillColor' => '#d6ead9',
|
||||
],
|
||||
];
|
||||
$pdf->addTaggedFigureContent(
|
||||
$pdf->graph->getStartTransform() . $pdf->graph->getRect($leftMargin, $figY, 180.0, 22.0, 'DF', $figStyle)
|
||||
. $pdf->graph->getStopTransform(),
|
||||
$pid4,
|
||||
'Horizontal bar chart illustrating the relative nesting depth of each PDF structure role category',
|
||||
[
|
||||
$pdf->toPoints($leftMargin),
|
||||
$pdf->toPoints($page4['height'] - $figY - 22.0),
|
||||
$pdf->toPoints($leftMargin + 180.0),
|
||||
$pdf->toPoints($page4['height'] - $figY),
|
||||
],
|
||||
);
|
||||
|
||||
$pdf->page->addContent($pdf->color->getPdfColor('black'), $pid4);
|
||||
$setFont($pdf, 'helvetica', 'I', 8);
|
||||
$pdf->beginStructElem(role: 'Caption', pid: $pid4);
|
||||
$pdf->addTextCell(
|
||||
'Figure 2 — Placeholder for a bar chart; /Alt text is written to the Figure struct-element dictionary',
|
||||
$pid4,
|
||||
$leftMargin,
|
||||
$figY + 24.0,
|
||||
0.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
);
|
||||
$pdf->endStructElem();
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,337 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E064_custom_hyphenation_dictionary.php
|
||||
*
|
||||
* @since 2026-05-01
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Demonstrate external TeX hyphenation pattern loading via
|
||||
* loadTexHyphenPatterns() + setTexHyphenPatterns().
|
||||
*
|
||||
* Background
|
||||
* ──────────
|
||||
* tc-lib-pdf inherits hyphenation support from the tc-lib-unicode library.
|
||||
* By default NO hyphenation patterns are loaded; hyphenation only occurs
|
||||
* when explicit soft-hyphens (­) are present in the source text
|
||||
* (see E028_text_hyphenation.php for that approach).
|
||||
*
|
||||
* When you call setTexHyphenPatterns() with a loaded pattern array, the
|
||||
* library automatically inserts soft-hyphen break points based on the
|
||||
* pattern rules while laying out each text run. This is especially useful
|
||||
* for narrow columns, justified text, or languages with long compound words
|
||||
* (German, Dutch, Finnish, etc.) where manual soft-hyphen insertion would
|
||||
* be impractical.
|
||||
*
|
||||
* API
|
||||
* ───
|
||||
* loadTexHyphenPatterns(string $file): array<string,string>
|
||||
* Parses a TeX .tex pattern file (the standard format used by CTAN
|
||||
* packages such as hyph-utf8) and returns a pattern array.
|
||||
* The file must contain a \patterns{ ... } block.
|
||||
*
|
||||
* setTexHyphenPatterns(array $patterns): void
|
||||
* Installs the pattern array as the active hyphenation dictionary.
|
||||
* Pass an empty array [] to disable automatic hyphenation.
|
||||
*
|
||||
* Full pattern files for ~100 languages are available from CTAN:
|
||||
* https://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/tex
|
||||
*
|
||||
* This example uses a small Dutch sample pattern file bundled with the
|
||||
* examples to keep the demo self-contained. The same technique works with
|
||||
* any complete CTAN TeX pattern file.
|
||||
*
|
||||
* Comparison layout
|
||||
* ─────────────────
|
||||
* The page shows the same Dutch paragraph rendered twice side by side:
|
||||
* Left column — NO patterns loaded (only explicit ­ break points)
|
||||
* Right column — Dutch sample patterns loaded via loadTexHyphenPatterns()
|
||||
*
|
||||
* Dutch is a good demonstration language because it has many long compound
|
||||
* words (e.g. "woordenschat", "zelfstandigheid", "werkgelegenheid") that
|
||||
* benefit greatly from automatic hyphenation in narrow columns.
|
||||
*/
|
||||
|
||||
// Path to the bundled sample Dutch TeX pattern file.
|
||||
$patternFile = \realpath(__DIR__ . '/data/hyph-nl-sample.tex');
|
||||
if ($patternFile === false) {
|
||||
throw new \RuntimeException('Missing pattern file: examples/data/hyph-nl-sample.tex');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Common document setup
|
||||
// -----------------------------------------------------------------------
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 064');
|
||||
$pdf->setTitle('Custom TeX Hyphenation Dictionary');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example hyphenation tex patterns dutch custom dictionary');
|
||||
$pdf->setPDFFilename('E064_custom_hyphenation_dictionary.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Load the Dutch pattern file BEFORE generating content.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Step 1: parse the .tex file into a pattern array.
|
||||
$dutchPatterns = $pdf->loadTexHyphenPatterns(file: $patternFile);
|
||||
|
||||
// Step 2: install as the active dictionary.
|
||||
$pdf->setTexHyphenPatterns(patterns: $dutchPatterns);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Fonts
|
||||
// -----------------------------------------------------------------------
|
||||
$fontTitle = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
$fontH2 = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 11);
|
||||
$fontBody = $pdf->font->insert($pdf->pon, 'times', '', 9);
|
||||
$fontCode = $pdf->font->insert($pdf->pon, 'courier', '', 8);
|
||||
$fontSmall = $pdf->font->insert($pdf->pon, 'helvetica', '', 8);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Dutch sample text — a paragraph with long compound words.
|
||||
// -----------------------------------------------------------------------
|
||||
$dutchPara =
|
||||
'De Nederlandse taal staat bekend om zijn lange samenstellingen. '
|
||||
. 'Woorden zoals woordenschatontwikkeling, zelfstandigheidsbewegingen, '
|
||||
. 'werkgelegenheidsbeleid, verantwoordelijkheidsgevoelens, '
|
||||
. 'maatschappelijkontwikkelingswerk en informatietechnologieonderwijs '
|
||||
. 'zijn perfecte voorbeelden van samenstellingen die automatische '
|
||||
. 'woordafbreking vereisen voor een goede leesbaarheid in smalle kolommen. '
|
||||
. 'Zonder patronen worden zulke woorden niet afgebroken en loopt de tekst '
|
||||
. 'over de kolomrand of ontstaan er grote witruimten bij uitgevulde tekst. '
|
||||
. 'Met de juiste TeX-patronen worden breekpunten automatisch ingevoegd '
|
||||
. 'op de linguistisch correcte syllabegrenzen van elk woord.';
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 1 — Side-by-side comparison
|
||||
// -----------------------------------------------------------------------
|
||||
$page1 = $pdf->addPage();
|
||||
|
||||
// --- Title ---
|
||||
$pdf->page->addContent($fontTitle['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Custom TeX Hyphenation Dictionary',
|
||||
15.0,
|
||||
18.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($fontSmall['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'loadTexHyphenPatterns() + setTexHyphenPatterns() — Dutch sample patterns vs no patterns',
|
||||
15.0,
|
||||
27.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// --- Column headers ---
|
||||
$pdf->page->addContent($fontH2['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'Without patterns',
|
||||
15.0,
|
||||
37.0,
|
||||
87.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
'With Dutch patterns',
|
||||
108.0,
|
||||
37.0,
|
||||
87.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
|
||||
// Separator line between header and body
|
||||
$sepStyle = [
|
||||
'lineWidth' => 0.3,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#336699',
|
||||
'fillColor' => '',
|
||||
];
|
||||
$pdf->page->addContent($pdf->graph->getLine(15.0, 43.5, 195.0, 43.5, $sepStyle));
|
||||
|
||||
// Vertical divider between columns
|
||||
$divStyle = [
|
||||
'lineWidth' => 0.2,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#aaaaaa',
|
||||
'fillColor' => '',
|
||||
];
|
||||
$pdf->page->addContent($pdf->graph->getLine(103.0, 44.0, 103.0, 200.0, $divStyle));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Left column — no automatic hyphenation
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Temporarily disable patterns.
|
||||
$pdf->setTexHyphenPatterns(patterns: []);
|
||||
|
||||
$leftHtml = '<div style="text-align:justify; font-size:9pt; color:#222222;">' . $dutchPara . '</div>';
|
||||
|
||||
// Re-insert non-bold font before left column addHTMLCell.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 9);
|
||||
$pdf->addHTMLCell(html: $leftHtml, posx: 15.0, posy: 45.0, width: 87.0);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Right column — Dutch patterns active
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Re-enable Dutch patterns.
|
||||
$pdf->setTexHyphenPatterns(patterns: $dutchPatterns);
|
||||
|
||||
$rightHtml = '<div style="text-align:justify; font-size:9pt; color:#222222;">' . $dutchPara . '</div>';
|
||||
|
||||
// Reset font stack to non-bold before second addHTMLCell.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 9);
|
||||
$pdf->addHTMLCell(html: $rightHtml, posx: 108.0, posy: 45.0, width: 87.0);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Pattern statistics block (below columns)
|
||||
// -----------------------------------------------------------------------
|
||||
$pdf->page->addContent($fontSmall['out']);
|
||||
|
||||
$patternCount = \count($dutchPatterns);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
"Pattern file: examples/data/hyph-nl-sample.tex | Patterns loaded: {$patternCount}"
|
||||
. ' | Source: CTAN hyph-utf8 (excerpt)',
|
||||
15.0,
|
||||
205.0,
|
||||
180.0,
|
||||
0.0,
|
||||
drawcell: false,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Center,
|
||||
));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Page 2 — API reference and usage guidance
|
||||
// -----------------------------------------------------------------------
|
||||
$page2 = $pdf->addPage();
|
||||
// Re-insert non-bold base font so the font stack is clean before addHTMLCell.
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 8);
|
||||
|
||||
$html2 = <<<'HTML'
|
||||
<h1 style="font-size:14pt; color:#003366;">API Reference and Usage Guidance</h1>
|
||||
|
||||
<h2 style="font-size:11pt; color:#005599;">loadTexHyphenPatterns(string $file): array</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Reads a TeX hyphenation pattern file and returns an associative array mapping
|
||||
pattern keys to their weighted strings. The file must contain a
|
||||
<code>\patterns{ ... }</code> block in standard TeX format. Comments
|
||||
(lines starting with <code>%</code>) are stripped before parsing.
|
||||
</p>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
The returned array can be stored and reused across multiple PDF objects
|
||||
without re-reading the file:
|
||||
</p>
|
||||
<pre style="font-size:8pt; color:#003366; background:#f0f4ff;">
|
||||
$patterns = $pdf->loadTexHyphenPatterns(lang: '/path/to/hyph-en-us.tex');
|
||||
$pdf->setTexHyphenPatterns(lang: $patterns);
|
||||
</pre>
|
||||
|
||||
<h2 style="font-size:11pt; color:#005599;">setTexHyphenPatterns(array $patterns): void</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Installs the pattern array as the active hyphenation dictionary. Hyphenation
|
||||
applies to all subsequent text layout calls. Pass an empty array
|
||||
<code>[]</code> to disable automatic hyphenation.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:11pt; color:#005599;">Obtaining pattern files</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
Full-quality pattern files for approximately 100 languages are available from
|
||||
the CTAN hyph-utf8 package:<br />
|
||||
<b>https://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/tex</b><br /><br />
|
||||
Notable files:
|
||||
</p>
|
||||
<table border="0" cellpadding="2">
|
||||
<tr><td style="font-size:8pt; width:55mm; color:#003366; font-weight:bold;">File</td>
|
||||
<td style="font-size:8pt; color:#003366; font-weight:bold;">Language</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-en-us.tex</td><td style="font-size:8pt;">English (US)</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-de-1996.tex</td><td style="font-size:8pt;">German (1996 reform)</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-nl.tex</td><td style="font-size:8pt;">Dutch</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-fr.tex</td><td style="font-size:8pt;">French</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-pl.tex</td><td style="font-size:8pt;">Polish</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-fi.tex</td><td style="font-size:8pt;">Finnish</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-pt.tex</td><td style="font-size:8pt;">Portuguese</td></tr>
|
||||
<tr><td style="font-size:8pt;">hyph-sv.tex</td><td style="font-size:8pt;">Swedish</td></tr>
|
||||
</table>
|
||||
|
||||
<h2 style="font-size:11pt; color:#005599;">Soft hyphens vs automatic patterns — when to use each</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
<b>&shy; (soft hyphens in HTML)</b> — best for single documents with known content
|
||||
where exact break points matter (e.g. trade-marked compound names, proper nouns
|
||||
that patterns would get wrong). See E028_text_hyphenation.php.<br /><br />
|
||||
<b>setTexHyphenPatterns()</b> — best for documents with large amounts of flowing
|
||||
text where manual annotation is impractical (articles, books, reports). Patterns
|
||||
are applied automatically to every word during layout without modifying the source
|
||||
string.
|
||||
</p>
|
||||
|
||||
<h2 style="font-size:11pt; color:#005599;">Switching languages mid-document</h2>
|
||||
<p style="font-size:9pt; color:#333333;">
|
||||
You can switch the active dictionary between pages or even between HTML cells
|
||||
by calling <code>setTexHyphenPatterns()</code> again with a different pattern
|
||||
array. Load all required pattern arrays at startup to avoid disk I/O during
|
||||
layout, then swap them as needed.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $html2, posx: 15.0, posy: 20.0, width: 180.0);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E065_import_single_page.php
|
||||
*
|
||||
* @since 2026-05-03
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// ---- Step 1: create a source PDF to import from ----
|
||||
|
||||
$src = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
$src->setCreator('tc-lib-pdf');
|
||||
$src->setAuthor('Nicola Asuni');
|
||||
$src->setSubject('tc-lib-pdf example: 065 source');
|
||||
$src->setTitle('Import Single Page - Source');
|
||||
$src->setKeywords('TCPDF tc-lib-pdf import single page source template');
|
||||
$src->setPDFFilename('065_import_single_page_src.pdf');
|
||||
$bfont = $src->font->insert($src->pon, 'helvetica', '', 14);
|
||||
|
||||
$srcPage = $src->addPage();
|
||||
$src->page->addContent($bfont['out']);
|
||||
$src->addHTMLCell(html: '<h1>Source document</h1><p>This page will be imported.</p>', posx: 15, posy: 20, width: 160);
|
||||
|
||||
$sourcePdfData = $src->getOutPDFString();
|
||||
|
||||
// ---- Step 2: create a new document and import the source page ----
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 065');
|
||||
$pdf->setTitle('Import Single Page - Destination');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf import single page destination cropbox template');
|
||||
$pdf->setPDFFilename('065_import_single_page.pdf');
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// Register the source document from its raw bytes.
|
||||
$sourceId = $pdf->setImportSourceData($sourcePdfData);
|
||||
|
||||
// Count pages available in the source.
|
||||
$pageCount = $pdf->getSourcePageCount($sourceId);
|
||||
|
||||
// Import page 1 as a reusable Form XObject template.
|
||||
$tpl = $pdf->importPage(sourceId: $sourceId, pageNum: 1);
|
||||
|
||||
// Add a new page to the destination document.
|
||||
$page = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// Place the imported page as a thumbnail (100 mm wide) at (20, 20).
|
||||
// The height is computed automatically to preserve the aspect ratio.
|
||||
$placed = $pdf->useImportedPage(tpl: $tpl, xpos: 20, ypos: 20, width: 140);
|
||||
|
||||
// Add an annotation below the imported page.
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p>Imported ' . $pageCount . ' page(s). Placed page 1 above (scaled).</p>',
|
||||
posx: 15,
|
||||
posy: (float) $placed['y'] + (float) $placed['height'] + 5,
|
||||
width: 160,
|
||||
);
|
||||
|
||||
// Get and render the PDF content.
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E066_import_document_append.php
|
||||
*
|
||||
* @since 2026-05-03
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// ---- Step 1: build a multi-page source PDF ----
|
||||
|
||||
$src = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
$src->setCreator('tc-lib-pdf');
|
||||
$src->setAuthor('Nicola Asuni');
|
||||
$src->setSubject('tc-lib-pdf example: 066 source');
|
||||
$src->setTitle('Import Document Append - Source');
|
||||
$src->setKeywords('TCPDF tc-lib-pdf import document append source template');
|
||||
$src->setPDFFilename('066_import_document_append_src.pdf');
|
||||
|
||||
$bfont = $src->font->insert($src->pon, 'helvetica', '', 14);
|
||||
|
||||
$pages = ['First page', 'Second page', 'Third page'];
|
||||
foreach ($pages as $idx => $label) {
|
||||
$srcPage = $src->addPage();
|
||||
$src->page->addContent($bfont['out']);
|
||||
$src->addHTMLCell(
|
||||
html: '<h2>Source: '
|
||||
. \htmlspecialchars($label)
|
||||
. '</h2>'
|
||||
. '<p>Page '
|
||||
. ($idx + 1)
|
||||
. ' of '
|
||||
. \count($pages)
|
||||
. ' in the source document.</p>',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 160,
|
||||
);
|
||||
}
|
||||
|
||||
$sourcePdfData = $src->getOutPDFString();
|
||||
|
||||
// ---- Step 2: create destination document with an intro page ----
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 066');
|
||||
$pdf->setTitle('Import Document Append - Destination');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf import append merge destination template');
|
||||
$pdf->setPDFFilename('066_import_document_append.pdf');
|
||||
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<h1>Document append demo</h1>' . '<p>The following pages are imported from a separate source document.</p>',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 160,
|
||||
);
|
||||
|
||||
// ---- Step 3: register source and append all its pages ----
|
||||
|
||||
$sourceId = $pdf->setImportSourceData($sourcePdfData);
|
||||
$pageCount = $pdf->getSourcePageCount($sourceId);
|
||||
|
||||
// appendDocument adds one new destination page per source page and places the template.
|
||||
$templates = $pdf->appendDocument($sourceId);
|
||||
|
||||
// ---- Step 4: add a closing page with a summary ----
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<p>Appended ' . \count($templates) . ' page(s) from source (' . $pageCount . ' available).</p>',
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 160,
|
||||
);
|
||||
|
||||
// Render
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E067_import_page_region_nup.php
|
||||
*
|
||||
* @since 2026-05-03
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// ---- Step 1: build a 4-page source document ----
|
||||
|
||||
$src = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
$src->setCreator('tc-lib-pdf');
|
||||
$src->setAuthor('Nicola Asuni');
|
||||
$src->setSubject('tc-lib-pdf example: 067 source');
|
||||
$src->setTitle('Import Page Region N-up - Source');
|
||||
$src->setKeywords('TCPDF tc-lib-pdf import page region nup source template');
|
||||
$src->setPDFFilename('067_import_page_region_nup_src.pdf');
|
||||
|
||||
$srcFont = $src->font->insert($src->pon, 'helvetica', '', 14);
|
||||
|
||||
$cards = [
|
||||
['title' => 'Card A', 'color' => '#ffd7b5', 'text' => 'Quarterly sales summary'],
|
||||
['title' => 'Card B', 'color' => '#b8f2e6', 'text' => 'Regional performance map'],
|
||||
['title' => 'Card C', 'color' => '#cde7ff', 'text' => 'Customer retention trends'],
|
||||
['title' => 'Card D', 'color' => '#f3d9fa', 'text' => 'Fulfillment and logistics KPIs'],
|
||||
];
|
||||
|
||||
foreach ($cards as $idx => $card) {
|
||||
$src->addPage();
|
||||
|
||||
// Colored background fill.
|
||||
$bgStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => $card['color'],
|
||||
'fillColor' => $card['color'],
|
||||
],
|
||||
];
|
||||
$src->page->addContent($src->graph->getRect(0, 0, 210, 297, 'F', $bgStyle));
|
||||
|
||||
// Render page content.
|
||||
$src->page->addContent($srcFont['out']);
|
||||
$src->addHTMLCell(
|
||||
html: '<h2>'
|
||||
. \htmlspecialchars($card['title'])
|
||||
. '</h2>'
|
||||
. '<p>'
|
||||
. \htmlspecialchars($card['text'])
|
||||
. '</p>'
|
||||
. '<p>Page '
|
||||
. ($idx + 1)
|
||||
. ' of '
|
||||
. \count($cards)
|
||||
. '</p>',
|
||||
posx: 20,
|
||||
posy: 40,
|
||||
width: 170,
|
||||
);
|
||||
}
|
||||
|
||||
$sourcePdfData = $src->getOutPDFString();
|
||||
|
||||
// ---- Step 2: import and compose a 2x2 N-up destination page ----
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 067');
|
||||
$pdf->setTitle('Import Page Region N-up - Destination');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf import page region nup destination imposition');
|
||||
$pdf->setPDFFilename('067_import_page_region_nup.pdf');
|
||||
|
||||
$labelFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$sourceId = $pdf->setImportSourceData($sourcePdfData);
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($labelFont['out']);
|
||||
|
||||
$margin = 12.0;
|
||||
$gap = 6.0;
|
||||
$gridWidth = 210.0 - (2 * $margin) - $gap;
|
||||
$gridHeight = 297.0 - (2 * $margin) - $gap;
|
||||
$cellWidth = $gridWidth / 2.0;
|
||||
$cellHeight = $gridHeight / 2.0;
|
||||
|
||||
$positions = [
|
||||
[$margin, $margin],
|
||||
[$margin + $cellWidth + $gap, $margin],
|
||||
[$margin, $margin + $cellHeight + $gap],
|
||||
[$margin + $cellWidth + $gap, $margin + $cellHeight + $gap],
|
||||
];
|
||||
|
||||
$borderStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.3,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#404040',
|
||||
'fillColor' => '',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($positions as $idx => [$x, $y]) {
|
||||
$tpl = $pdf->importPage(sourceId: $sourceId, pageNum: $idx + 1, options: ['box' => 'CropBox', 'cache' => true]);
|
||||
|
||||
$pdf->useImportedPage(tpl: $tpl, xpos: $x, ypos: $y, width: $cellWidth, height: $cellHeight, options: [
|
||||
'keepAspectRatio' => true,
|
||||
'align' => 'CC',
|
||||
'clip' => true,
|
||||
]);
|
||||
|
||||
// Draw outer cell frame over the imported content.
|
||||
$pdf->page->addContent($pdf->graph->getRect($x, $y, $cellWidth, $cellHeight, 'D', $borderStyle));
|
||||
|
||||
$pdf->page->addContent($labelFont['out']);
|
||||
$pdf->addHTMLCell(
|
||||
html: '<span style="font-size:9px">Imported page ' . ($idx + 1) . '</span>',
|
||||
posx: $x + 2,
|
||||
posy: $y + 2,
|
||||
width: 40,
|
||||
);
|
||||
}
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E068_font_subset.php
|
||||
*
|
||||
* @since 2026-05-04
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object with font subsetting enabled
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: true,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 068');
|
||||
$pdf->setTitle('Font Subsetting Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example font subsetting');
|
||||
$pdf->setPDFFilename('068_font_subset.pdf');
|
||||
|
||||
// Insert DejaVu Sans font for subsetting test
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'dejavusans', '', 12);
|
||||
|
||||
// Add first page
|
||||
$page = $pdf->addPage();
|
||||
|
||||
// Add font to the page
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// HTML content demonstrating varied character sets for subsetting
|
||||
$html = <<<'EOD'
|
||||
<h1>Font Subsetting Example</h1>
|
||||
<p>This document demonstrates <b>font subsetting</b> with DejaVu Sans font.</p>
|
||||
<p>Font subsetting reduces the file size by including only the characters
|
||||
that are actually used in the document, rather than embedding the entire font.</p>
|
||||
|
||||
<h2>Character Sets</h2>
|
||||
<p><b>English:</b> THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG - the quick brown fox jumps over the lazy dog.</p>
|
||||
<p><b>Numbers:</b> 0123456789 · π ≈ 3.14159</p>
|
||||
<p><b>Punctuation:</b> !@#$%^&*()[]{}–—«»‹›„“”‚‘’"'</p>
|
||||
<p><b>Symbols:</b> © ® ™ € £ ¥ ¢ § ¶ • ‰</p>
|
||||
|
||||
<h2>Benefits of Font Subsetting</h2>
|
||||
<ul>
|
||||
<li>Reduced PDF file size</li>
|
||||
<li>Faster document transmission</li>
|
||||
<li>Only embedded characters are included</li>
|
||||
<li>Maintains font fidelity for used characters</li>
|
||||
</ul>
|
||||
|
||||
<h2>Text Samples</h2>
|
||||
<p>Regular text in DejaVu Sans font for testing character coverage.</p>
|
||||
<p><b>Bold text</b> is also included in the subset.</p>
|
||||
EOD;
|
||||
|
||||
// render the HTML content
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 15, width: 180);
|
||||
|
||||
// Get the PDF content
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Render the PDF content
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E069_html_line_height.php
|
||||
*
|
||||
* @since 2026-04-27
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 069');
|
||||
$pdf->setTitle('HTML Line Height');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf html css line-height typography spacing');
|
||||
$pdf->setPDFFilename('069_html_line_height.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// Insert DejaVu Sans font for subsetting test
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'dejavusans', '', 12);
|
||||
|
||||
// Add first page
|
||||
$page = $pdf->addPage();
|
||||
|
||||
// Add font to the page
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$html = <<<EOF
|
||||
<h1>Line-Height CSS Tests</h1>
|
||||
<h2>1) Line-height with percentages</h2>
|
||||
<p style="line-height: 100%;">
|
||||
Line-height: 100%<br />
|
||||
This paragraph uses a line-height of 100%, which is the same as the font size.
|
||||
Each line should be tightly spaced without extra vertical space.
|
||||
This is useful when you want compact text layout.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 150%;">
|
||||
Line-height: 150%<br />
|
||||
This paragraph uses a line-height of 150%, which adds moderate spacing between lines.
|
||||
The lines are more readable and have better visual separation.
|
||||
This is a common default setting for body text in many documents.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 200%;">
|
||||
Line-height: 200%<br />
|
||||
This paragraph uses a line-height of 200%, which doubles the font size for vertical spacing.
|
||||
The lines have significant space between them, making the text very readable.
|
||||
This is often used for accessibility or when line spacing is deliberately increased.
|
||||
</p>
|
||||
|
||||
<h2>2) Line-height with absolute units</h2>
|
||||
<p style="line-height: 10pt;">
|
||||
Line-height: 10pt<br />
|
||||
This paragraph uses an absolute line-height of 10 points.
|
||||
The spacing between lines is fixed at exactly 10 points.
|
||||
The font size remains 10pt, so this creates tightly packed lines.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 15pt;">
|
||||
Line-height: 15pt<br />
|
||||
This paragraph uses an absolute line-height of 15 points.
|
||||
Each line has exactly 15 points of vertical space allocated.
|
||||
This provides moderate spacing for improved readability.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 20pt;">
|
||||
Line-height: 20pt<br />
|
||||
This paragraph uses an absolute line-height of 20 points.
|
||||
The lines are well-spaced with 20 points of vertical space each.
|
||||
This creates a more spacious and airy appearance in the document.
|
||||
</p>
|
||||
|
||||
<h2>3) Line-height with relative units (em)</h2>
|
||||
<p style="line-height: 0.8em;">
|
||||
Line-height: 0.8em<br />
|
||||
This paragraph uses a line-height of 0.8em, which is 80% of the current font size.
|
||||
The lines are compressed together with minimal vertical space.
|
||||
This is useful for creating a compact visual effect.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 1.2em;">
|
||||
Line-height: 1.2em<br />
|
||||
This paragraph uses a line-height of 1.2em, which is 120% of the current font size.
|
||||
The lines have a balanced amount of spacing for good readability.
|
||||
This is similar to using a 120% line-height percentage.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 2em;">
|
||||
Line-height: 2em<br />
|
||||
This paragraph uses a line-height of 2em, which is 200% of the current font size.
|
||||
The lines are widely separated with generous vertical spacing.
|
||||
This creates a very open and spacious text layout.
|
||||
</p>
|
||||
|
||||
<h2>4) Line-height with unitless numbers</h2>
|
||||
<p style="line-height: 0.9;">
|
||||
Line-height: 0.9 (unitless)<br />
|
||||
This paragraph uses a unitless line-height value of 0.9.
|
||||
The multiplier is applied to the font size (0.9 × 10pt = 9pt).
|
||||
This creates compact line spacing.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 1.5;">
|
||||
Line-height: 1.5 (unitless)<br />
|
||||
This paragraph uses a unitless line-height value of 1.5.
|
||||
The multiplier is applied to the font size (1.5 × 10pt = 15pt).
|
||||
This is a very popular setting for comfortable reading.
|
||||
The spacing is proportional to the font size.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 2.5;">
|
||||
Line-height: 2.5 (unitless)<br />
|
||||
This paragraph uses a unitless line-height value of 2.5.
|
||||
The multiplier is applied to the font size (2.5 × 10pt = 25pt).
|
||||
The lines are very widely spaced and easy to read.
|
||||
This is often used for accessibility requirements.
|
||||
</p>
|
||||
|
||||
<h2>5) Line-height with millimeters</h2>
|
||||
<p style="line-height: 5mm;">
|
||||
Line-height: 5mm<br />
|
||||
This paragraph uses an absolute line-height of 5 millimeters.
|
||||
The vertical spacing between lines is exactly 5mm.
|
||||
Different units like millimeters are sometimes used in print design.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 8mm;">
|
||||
Line-height: 8mm<br />
|
||||
This paragraph uses an absolute line-height of 8 millimeters.
|
||||
The increased spacing makes the text more readable and open.
|
||||
Millimeters are useful for precise layout control in documents.
|
||||
</p>
|
||||
|
||||
<h2>6) Comparison: normal vs specific values</h2>
|
||||
<p style="line-height: normal;">
|
||||
Line-height: normal<br />
|
||||
This paragraph uses the default line-height value (typically around 1.0-1.2).
|
||||
The spacing is determined by the browser or PDF renderer default.
|
||||
This is the baseline for comparison with other values.
|
||||
</p>
|
||||
|
||||
<p style="line-height: 1;">
|
||||
Line-height: 1 (unitless)<br />
|
||||
This paragraph uses a unitless line-height of exactly 1.
|
||||
The vertical space is the same as the font size.
|
||||
This creates tightly spaced lines with minimal separation.
|
||||
</p>
|
||||
|
||||
<div style="page-break-before:always;font-size:5mm;">
|
||||
<p style="color:black;">(1) default<br/>line<br/>height</p>
|
||||
<p style="color:grey; line-height:normal;">(2) normal<br/>line<br/>height</p>
|
||||
<p style="color:orange; line-height:100%;">(3) 100%<br/>line<br/>height</p>
|
||||
<p style="color:red; line-height:50%;">(4) 50%<br/>line<br/>height</p>
|
||||
<p style="color:green; line-height:150%;">(5) 150%<br/>line<br/>height</p>
|
||||
<p style="color:blue; line-height:10mm;">(6) 10mm<br/>line<br/>height</p>
|
||||
<p style="color:violet; line-height:20mm;">(7) 20mm<br/>line<br/>height</p>
|
||||
</div>
|
||||
|
||||
<div style="page-break-before:always;font-size:20mm;">
|
||||
<div style="line-height:20mm; color:green;">check<br/>line<br/>after<br/>BR</div>
|
||||
<div style="line-height:20mm; color:red;">check<br/>line<br/>after<div>DIV</div></div>
|
||||
</div>
|
||||
EOF;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 20, posy: 10, width: 150);
|
||||
|
||||
// ----------
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E070_default_page_content_import.php
|
||||
*
|
||||
* @since 2026-05-05
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
/**
|
||||
* Custom PDF class that imports and reuses a source page as default page content.
|
||||
*/
|
||||
class PdfWithImportedDefaultPage extends \Com\Tecnick\Pdf\Tcpdf
|
||||
{
|
||||
/** @var ?\Com\Tecnick\Pdf\Import\PageTemplateInterface */
|
||||
private $defaultTpl = null;
|
||||
|
||||
/**
|
||||
* Register source data and pick the page template to be used as default content.
|
||||
*
|
||||
* This uses the same import flow as E065:
|
||||
* - setImportSourceData(...)
|
||||
* - importPage(...)
|
||||
*
|
||||
* @param string $sourcePdfData Raw source PDF bytes.
|
||||
* @param int $sourcePageNum 1-based source page number to import.
|
||||
*/
|
||||
public function setDefaultImportedPage(string $sourcePdfData, int $sourcePageNum = 1): void
|
||||
{
|
||||
$sourceId = $this->setImportSourceData($sourcePdfData);
|
||||
$pageCount = $this->getSourcePageCount($sourceId);
|
||||
|
||||
if ($sourcePageNum < 1 || $sourcePageNum > $pageCount) {
|
||||
throw new \InvalidArgumentException('Requested source page is out of range. Available pages: '
|
||||
. $pageCount);
|
||||
}
|
||||
|
||||
$this->defaultTpl = $this->importPage(sourceId: $sourceId, pageNum: $sourcePageNum, options: [
|
||||
'box' => 'CropBox',
|
||||
'cache' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the imported template on every new page.
|
||||
*
|
||||
* @param int $pid Page index (0-based).
|
||||
*
|
||||
* @return string Empty stream; content is added directly by useImportedPage().
|
||||
*/
|
||||
public function defaultPageContent(int $pid = -1): string
|
||||
{
|
||||
if ($this->defaultTpl === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($pid < 0) {
|
||||
$pid = $this->page->getPageId();
|
||||
}
|
||||
|
||||
$page = $this->page->getPage($pid);
|
||||
|
||||
// Fill the whole destination page with the imported source page.
|
||||
$this->useImportedPage(
|
||||
tpl: $this->defaultTpl,
|
||||
xpos: 0.0,
|
||||
ypos: 0.0,
|
||||
width: (float) $page['width'],
|
||||
height: (float) $page['height'],
|
||||
options: [
|
||||
'keepAspectRatio' => true,
|
||||
'align' => 'CC',
|
||||
'clip' => true,
|
||||
],
|
||||
);
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Step 1: build a source PDF that will be imported ----
|
||||
|
||||
$src = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
$srcFont = $src->font->insert($src->pon, 'helvetica', '', 14);
|
||||
|
||||
$src->addPage();
|
||||
$src->page->addContent($srcFont['out']);
|
||||
$src->addHTMLCell(
|
||||
html: '<h1>Imported default page (source)</h1>'
|
||||
. '<p>This page is imported and reused as defaultPageContent() in E070.</p>',
|
||||
posx: 20,
|
||||
posy: 30,
|
||||
width: 170,
|
||||
);
|
||||
|
||||
$sourcePdfData = $src->getOutPDFString();
|
||||
|
||||
// ---- Step 2: create destination PDF using the custom subclass ----
|
||||
|
||||
$pdf = new PdfWithImportedDefaultPage('mm', true, false, true, '', null);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 070');
|
||||
$pdf->setTitle('Default Page Content from Imported PDF');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example import defaultPageContent template');
|
||||
$pdf->setPDFFilename('070_default_page_content_import.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
// Reuse source page 1 as the default page content for all pages.
|
||||
$pdf->setDefaultImportedPage($sourcePdfData, 1);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$bodyFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$titleFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 13);
|
||||
|
||||
// Page 1
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Page 1 - Foreground content',
|
||||
posx: 20,
|
||||
posy: 85,
|
||||
width: 170,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($bodyFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'The page background comes from an imported PDF page loaded via setImportSourceData() and importPage(), then applied in defaultPageContent().',
|
||||
posx: 20,
|
||||
posy: 95,
|
||||
width: 170,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 2,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
));
|
||||
|
||||
// Page 2
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Page 2 - Same imported default content',
|
||||
posx: 20,
|
||||
posy: 85,
|
||||
width: 170,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($bodyFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Because defaultPageContent() runs whenever addPage() is called, the imported source page is automatically placed on every new page.',
|
||||
posx: 20,
|
||||
posy: 95,
|
||||
width: 170,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 2,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E071_gettextcell_bbox_metrics.php
|
||||
*
|
||||
* @since 2026-05-06
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 071');
|
||||
$pdf->setTitle('getTextCell bbox metrics');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example getTextCell bbox textbbox cellbbox');
|
||||
$pdf->setPDFFilename('071_gettextcell_bbox_metrics.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$baseFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$titleFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
$textFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$monoFont = $pdf->font->insert($pdf->pon, 'courier', '', 10);
|
||||
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'E071: getTextCell multiline bbox metrics',
|
||||
posx: 20,
|
||||
posy: 20,
|
||||
width: 170,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($textFont['out']);
|
||||
|
||||
$blockStyles = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.4,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#006699',
|
||||
'fillColor' => '#f3f8fb',
|
||||
],
|
||||
];
|
||||
|
||||
// Custom cell arrays use internal points, so convert desired 5 mm padding first.
|
||||
$padding5mm = $pdf->toPoints(5.0);
|
||||
|
||||
$cellPadding5mm = [
|
||||
'margin' => [
|
||||
'T' => 0,
|
||||
'R' => 0,
|
||||
'B' => 0,
|
||||
'L' => 0,
|
||||
],
|
||||
'padding' => [
|
||||
'T' => $padding5mm,
|
||||
'R' => $padding5mm,
|
||||
'B' => $padding5mm,
|
||||
'L' => $padding5mm,
|
||||
],
|
||||
];
|
||||
|
||||
$multiline =
|
||||
'Line 1: This text uses getTextCell with automatic wrapping.'
|
||||
. "\n"
|
||||
. 'Line 2: The border is visible so the cell bounds can be compared.'
|
||||
. "\n"
|
||||
. 'Line 3: Metrics printed below come from getLastBBox(), getLastTextBBox(), and getLastCellBBox().';
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $multiline,
|
||||
posx: 20,
|
||||
posy: 35,
|
||||
width: 170,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1.5,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: $cellPadding5mm,
|
||||
styles: $blockStyles,
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
));
|
||||
|
||||
$bbox = $pdf->getLastBBox();
|
||||
$textbbox = $pdf->getLastTextBBox();
|
||||
$cellbbox = $pdf->getLastCellBBox();
|
||||
|
||||
$fmtMetric = static fn(float $value): string => \sprintf('%7.3F', $value);
|
||||
|
||||
$pdf->page->addContent($monoFont['out']);
|
||||
|
||||
$metricsText =
|
||||
'bbox : x='
|
||||
. $fmtMetric($bbox['x'])
|
||||
. ' y='
|
||||
. $fmtMetric($bbox['y'])
|
||||
. ' w='
|
||||
. $fmtMetric($bbox['w'])
|
||||
. ' h='
|
||||
. $fmtMetric($bbox['h'])
|
||||
. "\n"
|
||||
. 'textbbox : x='
|
||||
. $fmtMetric($textbbox['x'])
|
||||
. ' y='
|
||||
. $fmtMetric($textbbox['y'])
|
||||
. ' w='
|
||||
. $fmtMetric($textbbox['w'])
|
||||
. ' h='
|
||||
. $fmtMetric($textbbox['h'])
|
||||
. "\n"
|
||||
. 'cellbbox : x='
|
||||
. $fmtMetric($cellbbox['x'])
|
||||
. ' y='
|
||||
. $fmtMetric($cellbbox['y'])
|
||||
. ' w='
|
||||
. $fmtMetric($cellbbox['w'])
|
||||
. ' h='
|
||||
. $fmtMetric($cellbbox['h']);
|
||||
|
||||
$metricsPosY = $cellbbox['y'] + $cellbbox['h'] + 8;
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $metricsText,
|
||||
posx: 20,
|
||||
posy: $metricsPosY,
|
||||
width: 170,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E072_import_new_font.php
|
||||
*
|
||||
* Demonstrates a direct custom-font workflow:
|
||||
* 1. Download Noto Sans Regular.
|
||||
* 2. Convert it with tc-lib-pdf-font.
|
||||
* 3. Start a PDF page and render text using that imported font.
|
||||
*
|
||||
* @since 2026-05-06
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$defaultFontsDir = (string) \realpath(\dirname(__DIR__) . '/vendor/tecnickcom/tc-lib-pdf-font/target/fonts');
|
||||
$sourceFontsDir = \dirname(__DIR__) . '/target/fonts/source';
|
||||
$customFontsDir = \dirname(__DIR__) . '/target/fonts/custom';
|
||||
$notoFileName = 'NotoSans-Regular.ttf';
|
||||
$notoUrl = 'https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSans/NotoSans-Regular.ttf';
|
||||
$notoSourcePath = $sourceFontsDir . '/' . $notoFileName;
|
||||
$fontFamily = 'notosans';
|
||||
$fontSetupError = '';
|
||||
$customFontsReal = '';
|
||||
|
||||
/**
|
||||
* Download a file from URL to local destination.
|
||||
*
|
||||
* @throws RuntimeException in case of download failure
|
||||
*/
|
||||
function downloadFile(string $url, string $destination, int $timeout = 30): void
|
||||
{
|
||||
$ctx = \stream_context_create([
|
||||
'http' => [
|
||||
'follow_location' => 1,
|
||||
'max_redirects' => 5,
|
||||
'timeout' => $timeout,
|
||||
],
|
||||
]);
|
||||
|
||||
$data = @\file_get_contents($url, false, $ctx);
|
||||
if ($data === false) {
|
||||
throw new \RuntimeException('Unable to download font from: ' . $url);
|
||||
}
|
||||
|
||||
if (@\file_put_contents($destination, $data) === false) {
|
||||
throw new \RuntimeException('Unable to save downloaded font to: ' . $destination);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!\is_dir($sourceFontsDir)) {
|
||||
if (!@\mkdir($sourceFontsDir, 0755, true) && !\is_dir($sourceFontsDir)) {
|
||||
throw new \RuntimeException('Unable to create directory: ' . $sourceFontsDir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!\is_dir($customFontsDir)) {
|
||||
if (!@\mkdir($customFontsDir, 0755, true) && !\is_dir($customFontsDir)) {
|
||||
throw new \RuntimeException('Unable to create directory: ' . $customFontsDir);
|
||||
}
|
||||
}
|
||||
|
||||
$customFontsReal = (string) \realpath($customFontsDir);
|
||||
if (empty($customFontsReal)) {
|
||||
throw new \RuntimeException('Unable to resolve custom fonts directory path.');
|
||||
}
|
||||
|
||||
$convertedFontPath = $customFontsReal . '/' . $fontFamily . '.json';
|
||||
|
||||
// 1) Download Noto Sans Regular only when needed.
|
||||
if (!\is_file($convertedFontPath) && !\is_file($notoSourcePath)) {
|
||||
downloadFile($notoUrl, $notoSourcePath, 60);
|
||||
}
|
||||
|
||||
// 2) Convert it to tc-lib-pdf-font format when not already converted.
|
||||
if (!\is_file($convertedFontPath)) {
|
||||
$sourceFontPath = (string) \realpath($notoSourcePath);
|
||||
if (empty($sourceFontPath)) {
|
||||
throw new \RuntimeException('Unable to resolve downloaded font path.');
|
||||
}
|
||||
|
||||
try {
|
||||
$import = new \Com\Tecnick\Pdf\Font\Import(
|
||||
$sourceFontPath,
|
||||
$customFontsReal . '/',
|
||||
'TrueTypeUnicode',
|
||||
'',
|
||||
32,
|
||||
3,
|
||||
1,
|
||||
false,
|
||||
);
|
||||
$fontFamily = $import->getFontName();
|
||||
$convertedFontPath = $customFontsReal . '/' . $fontFamily . '.json';
|
||||
} catch (\Throwable $e) {
|
||||
$alreadyImported = \strpos($e->getMessage(), 'already imported:') !== false;
|
||||
if ($alreadyImported && \preg_match('/([a-z0-9_\-]+)\.json$/i', $e->getMessage(), $match) === 1) {
|
||||
$fontFamily = \strtolower((string) $match[1]);
|
||||
$convertedFontPath = $customFontsReal . '/' . $fontFamily . '.json';
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!\is_file($convertedFontPath)) {
|
||||
throw new \RuntimeException('Converted font definition file not found: ' . $convertedFontPath);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$fontSetupError = $e->getMessage();
|
||||
}
|
||||
|
||||
if (empty($fontSetupError) && !empty($customFontsReal)) {
|
||||
// The HTML <pre> tag defaults to courier in this renderer.
|
||||
// Copy core courier metrics into the custom font directory when missing.
|
||||
$defaultCourier = $defaultFontsDir . '/core/courier.json';
|
||||
$customCourier = $customFontsReal . '/courier.json';
|
||||
if (\is_file($defaultCourier) && !\is_file($customCourier)) {
|
||||
@\copy($defaultCourier, $customCourier);
|
||||
}
|
||||
}
|
||||
|
||||
$fontsRoot = !empty($fontSetupError) || empty($customFontsReal) ? $defaultFontsDir : $customFontsReal;
|
||||
\define('K_PATH_FONTS', $fontsRoot);
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: true,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 072');
|
||||
$pdf->setTitle('Import and Use a New Font');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf font import custom ttf otf noto sans');
|
||||
$pdf->setPDFFilename('072_import_new_font.pdf');
|
||||
|
||||
$manualFontFamily = !empty($fontSetupError) ? 'helvetica' : $fontFamily;
|
||||
|
||||
$manualInstructions =
|
||||
'<p style="font-family: '
|
||||
. \htmlspecialchars($manualFontFamily, ENT_QUOTES)
|
||||
. ';">Manual conversion and import commands:</p>'
|
||||
. '<p style="font-family: '
|
||||
. \htmlspecialchars($manualFontFamily, ENT_QUOTES)
|
||||
. ';">Run these commands from the project root:</p>'
|
||||
. '<pre style="color:darkgreen;font-family: '
|
||||
. \htmlspecialchars($manualFontFamily, ENT_QUOTES)
|
||||
. '; font-size: 9pt; line-height: 1.35;">'
|
||||
. 'mkdir -p target/fonts/source target/fonts/custom'
|
||||
. "\n\n"
|
||||
. 'curl -fL --retry 3 -o target/fonts/source/'
|
||||
. \htmlspecialchars($notoFileName, ENT_QUOTES)
|
||||
. ' '
|
||||
. \htmlspecialchars($notoUrl, ENT_QUOTES)
|
||||
. "\n\n"
|
||||
. 'php vendor/tecnickcom/tc-lib-pdf-font/util/convert.php \\'
|
||||
. "\n"
|
||||
. ' --outpath=target/fonts/custom \\'
|
||||
. "\n"
|
||||
. ' --type=TrueTypeUnicode \\'
|
||||
. "\n"
|
||||
. ' --flags=32 \\'
|
||||
. "\n"
|
||||
. ' --encoding_id=1 \\'
|
||||
. "\n"
|
||||
. ' --fonts=target/fonts/source/'
|
||||
. \htmlspecialchars($notoFileName, ENT_QUOTES)
|
||||
. '</pre>'
|
||||
. '<p style="font-family: '
|
||||
. \htmlspecialchars($manualFontFamily, ENT_QUOTES)
|
||||
. ';">Then run this example again; it will load the generated '
|
||||
. 'target/fonts/custom/'
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. '.json.</p>';
|
||||
|
||||
if (!empty($fontSetupError)) {
|
||||
$baseFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
$pdf->page->addContent($baseFont['out']);
|
||||
|
||||
$html =
|
||||
'<h1 style="font-family: helvetica;">Font Setup Failed</h1>'
|
||||
. '<p style="font-family: helvetica;">The example could not download or convert Noto Sans automatically.</p>'
|
||||
. '<p style="font-family: helvetica;"><b>Error:</b> '
|
||||
. \htmlspecialchars($fontSetupError, ENT_QUOTES)
|
||||
. '</p>'
|
||||
. '<p style="font-family: helvetica;">If the environment is offline, run once with internet access or pre-populate:</p>'
|
||||
. '<p style="font-family: helvetica;">target/fonts/source/'
|
||||
. \htmlspecialchars($notoFileName, ENT_QUOTES)
|
||||
. ' and target/fonts/custom/'
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. '.json.</p>'
|
||||
. '<hr/>'
|
||||
. $manualInstructions;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
return;
|
||||
}
|
||||
|
||||
$notoFont = $pdf->font->insert($pdf->pon, $fontFamily, '', 10);
|
||||
|
||||
// 3) Start the PDF page and render content using the imported font.
|
||||
$pdf->addPage(['format' => 'A4']);
|
||||
$pdf->page->addContent($notoFont['out']);
|
||||
|
||||
$html =
|
||||
'<h1 style="font-family: '
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. ';">Custom Font Imported Automatically</h1>'
|
||||
. '<p style="font-family: '
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. ';">Downloaded from: '
|
||||
. \htmlspecialchars($notoUrl, ENT_QUOTES)
|
||||
. '</p>'
|
||||
. '<p style="font-family: '
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. ';">Converted source: target/fonts/source/'
|
||||
. \htmlspecialchars($notoFileName, ENT_QUOTES)
|
||||
. '</p>'
|
||||
. '<p style="font-family: '
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. ';">Imported family: <b>'
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. '</b></p>'
|
||||
. '<hr/>'
|
||||
. '<p style="font-family: '
|
||||
. \htmlspecialchars($fontFamily, ENT_QUOTES)
|
||||
. '; font-size: 16pt;">'
|
||||
. 'The quick brown fox jumps over the lazy dog. 0123456789'
|
||||
. '</p>'
|
||||
. '<hr/>'
|
||||
. $manualInstructions;
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E074_text_cell_fit_modes.php
|
||||
*
|
||||
* Demonstrates getTextCell/addTextCell fit modes:
|
||||
* T, S, F and disabled behavior.
|
||||
*
|
||||
* @since 2026-05-19
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 074');
|
||||
$pdf->setTitle('Text Cell Fit Modes');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example text cell fit T S F');
|
||||
$pdf->setPDFFilename('074_text_cell_fit_modes.pdf');
|
||||
|
||||
$titleFont = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 14);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'getTextCell() fit mode',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$baseFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
|
||||
$cellStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.3,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#4a5b70',
|
||||
'fillColor' => '#ffffff',
|
||||
],
|
||||
];
|
||||
|
||||
$pdf->page->addContent($baseFont['out']);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Long text scenario (overflow):',
|
||||
posx: 15,
|
||||
posy: 30,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$longSample = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
|
||||
$modesL = [
|
||||
\Com\Tecnick\Pdf\TextFitMode::Truncate,
|
||||
\Com\Tecnick\Pdf\TextFitMode::Stretch,
|
||||
\Com\Tecnick\Pdf\TextFitMode::ShrinkFont,
|
||||
\Com\Tecnick\Pdf\TextFitMode::Off,
|
||||
];
|
||||
$modeY = 40;
|
||||
|
||||
foreach ($modesL as $mode) {
|
||||
$label = $mode === \Com\Tecnick\Pdf\TextFitMode::Off ? 'fit=(disabled)' : 'fit=' . $mode->value;
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $label,
|
||||
posx: 15,
|
||||
posy: $modeY,
|
||||
width: 24,
|
||||
height: 6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
));
|
||||
|
||||
// one line
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $longSample,
|
||||
posx: 41,
|
||||
posy: $modeY,
|
||||
width: 160,
|
||||
height: 5,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
));
|
||||
|
||||
// multiple lines
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $longSample,
|
||||
posx: 41,
|
||||
posy: $modeY + 8,
|
||||
width: 80,
|
||||
height: 10,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
));
|
||||
|
||||
$modeY += 25;
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
$pid = $page['pid'];
|
||||
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'addTextCell() fit mode',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($baseFont['out']);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Long text scenario (overflow):',
|
||||
posx: 15,
|
||||
posy: 30,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$modeY = 40;
|
||||
|
||||
foreach ($modesL as $mode) {
|
||||
$label = $mode === \Com\Tecnick\Pdf\TextFitMode::Off ? 'fit=(disabled)' : 'fit=' . $mode->value;
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $label,
|
||||
posx: 15,
|
||||
posy: $modeY,
|
||||
width: 24,
|
||||
height: 6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
));
|
||||
|
||||
// one line
|
||||
$pdf->addTextCell(
|
||||
txt: $longSample,
|
||||
pid: $pid,
|
||||
posx: 41,
|
||||
posy: $modeY,
|
||||
width: 160,
|
||||
height: 5,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
);
|
||||
|
||||
// multiple lines
|
||||
$pdf->addTextCell(
|
||||
txt: $longSample,
|
||||
pid: $pid,
|
||||
posx: 41,
|
||||
posy: $modeY + 8,
|
||||
width: 80,
|
||||
height: 10,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
);
|
||||
|
||||
$modeY += 25;
|
||||
}
|
||||
|
||||
// ----------
|
||||
// /\/\/\/\/\
|
||||
// ----------
|
||||
|
||||
$pdf->addPage();
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'getTextCell() fit mode long word (hyphenated)',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$baseFont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
|
||||
$cellStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.3,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => '#4a5b70',
|
||||
'fillColor' => '#ffffff',
|
||||
],
|
||||
];
|
||||
|
||||
$pdf->page->addContent($baseFont['out']);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Long word scenario (overflow):',
|
||||
posx: 15,
|
||||
posy: 30,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
// Define a custom hyphenation pattern that splits a word after each character.
|
||||
// See loadTexHyphenPatterns() for language-specific hyphenation patterns.
|
||||
$singleCharPattern = [];
|
||||
foreach (range('a', 'z') as $letter) {
|
||||
$singleCharPattern[$letter] = $letter . '1';
|
||||
}
|
||||
$pdf->setTexHyphenPatterns(patterns: $singleCharPattern);
|
||||
|
||||
$longWord = 'Loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua.';
|
||||
$modesL = [
|
||||
\Com\Tecnick\Pdf\TextFitMode::Truncate,
|
||||
\Com\Tecnick\Pdf\TextFitMode::Stretch,
|
||||
\Com\Tecnick\Pdf\TextFitMode::ShrinkFont,
|
||||
\Com\Tecnick\Pdf\TextFitMode::Off,
|
||||
];
|
||||
$modeY = 40;
|
||||
|
||||
foreach ($modesL as $mode) {
|
||||
$label = $mode === \Com\Tecnick\Pdf\TextFitMode::Off ? 'fit=(disabled)' : 'fit=' . $mode->value;
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $label,
|
||||
posx: 15,
|
||||
posy: $modeY,
|
||||
width: 24,
|
||||
height: 6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
));
|
||||
|
||||
// one line
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $longWord,
|
||||
posx: 41,
|
||||
posy: $modeY,
|
||||
width: 160,
|
||||
height: 5,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
));
|
||||
|
||||
// multiple lines
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $longWord,
|
||||
posx: 41,
|
||||
posy: $modeY + 8,
|
||||
width: 80,
|
||||
height: 10,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
));
|
||||
|
||||
$modeY += 25;
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
$page = $pdf->addPage();
|
||||
$pid = $page['pid'];
|
||||
|
||||
$pdf->page->addContent($titleFont['out']);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'addTextCell() fit mode long word (hyphenated)',
|
||||
posx: 15,
|
||||
posy: 15,
|
||||
width: 180,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$pdf->page->addContent($baseFont['out']);
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: 'Long word scenario (overflow):',
|
||||
posx: 15,
|
||||
posy: 30,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
$modeY = 40;
|
||||
|
||||
foreach ($modesL as $mode) {
|
||||
$label = $mode === \Com\Tecnick\Pdf\TextFitMode::Off ? 'fit=(disabled)' : 'fit=' . $mode->value;
|
||||
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $label,
|
||||
posx: 15,
|
||||
posy: $modeY,
|
||||
width: 24,
|
||||
height: 6,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
));
|
||||
|
||||
// one line
|
||||
$pdf->addTextCell(
|
||||
txt: $longWord,
|
||||
pid: $pid,
|
||||
posx: 41,
|
||||
posy: $modeY,
|
||||
width: 160,
|
||||
height: 5,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
);
|
||||
|
||||
// multiple lines
|
||||
$pdf->addTextCell(
|
||||
txt: $longWord,
|
||||
pid: $pid,
|
||||
posx: 41,
|
||||
posy: $modeY + 8,
|
||||
width: 80,
|
||||
height: 10,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
styles: $cellStyle,
|
||||
fit: $mode,
|
||||
);
|
||||
|
||||
$modeY += 25;
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E075_external_signature_injection.php
|
||||
*
|
||||
* Demonstrates a remote/external signing workflow using a signature placeholder,
|
||||
* ByteRange hash export, and later CMS/PKCS#7 injection.
|
||||
*
|
||||
* @since 2026-05-28
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 075');
|
||||
$pdf->setTitle('External Signature Injection Workflow');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example external signature remote pkcs7 byterange');
|
||||
$pdf->setPDFFilename('E075_signed_external_signature_injection.pdf');
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
$page = $pdf->addPage(['format' => 'A4']);
|
||||
|
||||
$basefont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
$pdf->page->addContent($basefont['out']);
|
||||
|
||||
$pdf->setSignatureForExternalSigning([
|
||||
'cert_type' => 2,
|
||||
'info' => [
|
||||
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
'Location' => 'Remote signing service',
|
||||
'Name' => 'External Signer',
|
||||
'Reason' => 'Remote detached CMS signature injection demo',
|
||||
],
|
||||
'password' => '',
|
||||
'privkey' => '',
|
||||
'signcert' => '',
|
||||
]);
|
||||
|
||||
$sigPosX = 100.0;
|
||||
$sigPosY = 220.0;
|
||||
$sigWidth = 80.0;
|
||||
$sigHeight = 20.0;
|
||||
|
||||
$pdf->setSignatureAppearance(
|
||||
posx: $sigPosX,
|
||||
posy: $sigPosY,
|
||||
width: $sigWidth,
|
||||
height: $sigHeight,
|
||||
page: $page['pid'],
|
||||
name: 'Remote Approval',
|
||||
);
|
||||
|
||||
// Custom /AP stream to make the signature widget visually obvious.
|
||||
$sigStamp = \gmdate('Y-m-d H:i:s') . ' UTC';
|
||||
$sigTopY = $page['height'] - $sigHeight;
|
||||
|
||||
// Build the signature appearance stream directly from HTML table markup.
|
||||
$sigAppearance = $basefont['out'];
|
||||
|
||||
$sigTableHtml = <<<HTML
|
||||
<table border="1" cellpadding="1" cellspacing="0" style="width:80mm; border-color:#183a66; color:#1f2a33; font-size:9pt;">
|
||||
<tr>
|
||||
<td style="width:40mm;background-color:#d4e8ff;"><b>REMOTE SIGNATURE</b></td>
|
||||
<td style="width:40mm;background-color:#a9d0ff;text-align:center;"><b>CMS/PKCS#7</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="background-color:#ffffcc;">External signature provider</td>
|
||||
</tr>
|
||||
<tr style="background-color:#ccffcc;">
|
||||
<td style="width:40mm;">Prepared:</td>
|
||||
<td style="width:40mm;text-align:center;"><b>{$sigStamp}</b></td>
|
||||
</tr>
|
||||
</table>
|
||||
HTML;
|
||||
|
||||
$sigAppearance .= $pdf->getHTMLCell(html: $sigTableHtml, posx: 0, posy: $sigTopY, width: $sigWidth, height: $sigHeight);
|
||||
$pdf->setSignatureAppearanceStream(stream: $sigAppearance);
|
||||
|
||||
$instructionsHtml = <<<HTML
|
||||
<h1>External Signature Injection (E075)</h1>
|
||||
<p>This example demonstrates a full remote-signing flow where the private key never lives in your
|
||||
application. The signature field uses the ISO 32000-1 <code>/adbe.pkcs7.detached</code> sub-filter.</p>
|
||||
|
||||
<h2>Workflow</h2>
|
||||
<ol>
|
||||
<li><b>Create placeholder</b><br />
|
||||
Configure a signature field and reserve <code>/Contents</code> bytes using
|
||||
<code>setSignatureForExternalSigning()</code> and <code>setSignatureAppearance()</code>.</li>
|
||||
<li><b>Prepare and hash</b><br />
|
||||
Call <code>getExternalSignaturePreparation('sha256')</code> to receive:
|
||||
<ul>
|
||||
<li>prepared PDF bytes with final <code>/ByteRange</code>,</li>
|
||||
<li>the exact <code>byte_range</code> tuple,</li>
|
||||
<li>digest in raw, hex, and base64 formats.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>Remote sign</b><br />
|
||||
Send the digest (typically <code>hash_base64</code>) to your external provider,
|
||||
such as HSM/KMS or gov.br signing API, and receive CMS/PKCS#7 detached signature bytes.</li>
|
||||
<li><b>Inject signature</b><br />
|
||||
Call <code>applyExternalSignature(preparedPdf, byteRange, cmsSignature, encoding)</code>
|
||||
with <code>encoding = binary|base64|hex</code> to produce the final signed PDF bytes.</li>
|
||||
</ol>
|
||||
|
||||
<h2>This Demo Uses a Fake External Response</h2>
|
||||
<p>To keep the example self-contained and offline, it injects a simulated CMS payload
|
||||
(<code>DEMO-REMOTE-CMS:</code> followed by the raw digest) instead of calling a real signer. The injection
|
||||
reuses the reserved <code>/Contents</code> placeholder without re-hashing the document, so the PDF proves
|
||||
the ByteRange / placeholder / injection mechanics but is cryptographically invalid and will not pass
|
||||
signature validation. <code>applyExternalSignature()</code> throws if the returned CMS is larger than the
|
||||
reserved placeholder, so size the placeholder for your provider's real CMS.</p>
|
||||
|
||||
<h2>Run Modes</h2>
|
||||
<ul>
|
||||
<li><b>CLI default:</b> <code>save</code> mode writes both prepared and signed files under <code>target/</code>.</li>
|
||||
<li><b>CLI explicit:</b> <code>php examples/E075_external_signature_injection.php save</code> or <code>render</code>.</li>
|
||||
<li><b>Web:</b> append <code>?mode=save</code> or <code>?mode=render</code>.</li>
|
||||
</ul>
|
||||
HTML;
|
||||
|
||||
$pdf->addHTMLCell(html: $instructionsHtml, posx: 15, posy: 20, width: 180);
|
||||
|
||||
$mode = PHP_SAPI === 'cli' ? 'save' : 'render';
|
||||
if (PHP_SAPI === 'cli') {
|
||||
$mode = (string) ($argv[1] ?? 'save');
|
||||
} elseif (isset($_GET['mode']) && is_string($_GET['mode'])) {
|
||||
$mode = $_GET['mode'];
|
||||
}
|
||||
|
||||
$mode = strtolower(trim($mode));
|
||||
if (!in_array($mode, ['render', 'save'], true)) {
|
||||
$mode = PHP_SAPI === 'cli' ? 'save' : 'render';
|
||||
}
|
||||
|
||||
// The external signing workflow (reserve placeholder, hash, remote-sign, inject)
|
||||
// is documented in the instructions rendered into the document above.
|
||||
$prepared = $pdf->getExternalSignaturePreparation('sha256');
|
||||
|
||||
// Demo shortcut: inject a FAKE CMS payload instead of calling a real signer (see
|
||||
// the "fake external response" note in the rendered instructions above). Replace
|
||||
// this with a real CMS from your provider for a verifiable signature.
|
||||
$fakeRemoteCmsSignature = 'DEMO-REMOTE-CMS:' . $prepared['hash_raw'];
|
||||
$signedPdf = $pdf->applyExternalSignature(
|
||||
preparedPdf: $prepared['prepared_pdf'],
|
||||
byteRange: $prepared['byte_range'],
|
||||
signature: $fakeRemoteCmsSignature,
|
||||
encoding: \Com\Tecnick\Pdf\Signature\ExternalSignatureEncoding::Binary,
|
||||
);
|
||||
|
||||
if ($mode === 'save') {
|
||||
$targetDir = \dirname(__DIR__) . '/target';
|
||||
if (!is_dir($targetDir)) {
|
||||
mkdir($targetDir, 0777, true);
|
||||
}
|
||||
|
||||
$preparedPath = $targetDir . '/E075_prepared_unsigned_external_signature.pdf';
|
||||
$signedPath = $targetDir . '/E075_signed_demo_external_signature_injection.pdf';
|
||||
|
||||
file_put_contents($preparedPath, $prepared['prepared_pdf']);
|
||||
file_put_contents($signedPath, $signedPdf);
|
||||
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
}
|
||||
|
||||
echo "Prepared PDF: {$preparedPath}\n";
|
||||
echo "Signed PDF: {$signedPath}\n";
|
||||
echo 'Digest (sha256, base64): ' . $prepared['hash_base64'] . "\n";
|
||||
echo "\n";
|
||||
echo "Note: Signed output uses a simulated external CMS payload for demo purposes.\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
$pdf->renderPDF(rawpdf: $signedPdf);
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E076_absolute_position.php
|
||||
*
|
||||
* @since 2026-04-19
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 076');
|
||||
$pdf->setTitle('Minimal Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf absolute position');
|
||||
$pdf->setPDFFilename('076_absolute_position.pdf');
|
||||
|
||||
// Line style
|
||||
$style1 = [
|
||||
'lineWidth' => 0.5,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'green',
|
||||
'fillColor' => 'blue',
|
||||
];
|
||||
|
||||
// Insert font
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
|
||||
|
||||
// ----------
|
||||
|
||||
// Add first page in Portrait mode (P)
|
||||
$pageP = $pdf->addPage(['format' => 'A4', 'orientation' => 'P']);
|
||||
|
||||
// Add font to the page
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
// Draw page diagonals
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, 0, $pageP['width'], $pageP['height'], $style1));
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, $pageP['height'], $pageP['width'], 0, $style1));
|
||||
|
||||
// ----------
|
||||
|
||||
// Add first page in Landscape mode (L)
|
||||
$pageL = $pdf->addPage(['format' => 'A4', 'orientation' => 'L']);
|
||||
|
||||
// Draw page diagonals
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, 0, $pageL['width'], $pageL['height'], $style1));
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, $pageL['height'], $pageL['width'], 0, $style1));
|
||||
|
||||
// /\/\/\/\/\
|
||||
|
||||
// Add content to previous pages
|
||||
|
||||
// ----------
|
||||
|
||||
// Select the page to change
|
||||
$pgP = $pdf->setCurrentPage($pageP['pid']);
|
||||
|
||||
$cxP = $pgP['width'] / 2;
|
||||
$cyP = $pgP['height'] / 2;
|
||||
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell('THIS TEXT TOP-LEFT STARTS AT THE PAGE CENTER POINT', $cxP, $cyP),
|
||||
$pgP['pid'],
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pgL = $pdf->setCurrentPage($pageL['pid']);
|
||||
|
||||
$cxL = $pgL['width'] / 2;
|
||||
$cyL = $pgL['height'] / 2;
|
||||
|
||||
$pdf->page->addContent(
|
||||
$pdf->getTextCell('THIS TEXT TOP-LEFT STARTS AT THE PAGE CENTER POINT', $cxL, $cyL),
|
||||
$pgL['pid'],
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
// Get the PDF content
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Render the PDF content
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E077_html_table_header_px_unit.php
|
||||
*
|
||||
* @since 2026-06-12
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\define('OUTPUT_FILE', \realpath(__DIR__ . '/../target') . '/example.pdf');
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
//
|
||||
// The 'px' document unit maps one user unit to one PDF point, while CSS
|
||||
// pixel lengths use the standard 96dpi ratio (1px = 0.75pt). This example
|
||||
// verifies that replayed table headers on continuation pages keep the same
|
||||
// column geometry as the table body regardless of the document unit
|
||||
// (see https://github.com/tecnickcom/tc-lib-pdf/issues/224).
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Point,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 077');
|
||||
$pdf->setTitle('HTML Table Header with PX Unit');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf html table thead header pixel px unit pagination');
|
||||
$pdf->setPDFFilename('077_html_table_header_px_unit.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
$pdf->enableDefaultPageContent();
|
||||
|
||||
// ----------
|
||||
// Insert fonts
|
||||
|
||||
// A small custom page so the table spans several pages.
|
||||
$pageV01 = $pdf->addPage(['height' => 300, 'width' => 400]);
|
||||
|
||||
$bfont6 = $pdf->font->insert($pdf->pon, 'dejavusans', '', 6);
|
||||
|
||||
$pdf->page->addContent($bfont6['out']);
|
||||
|
||||
// =============================================================
|
||||
// Table spanning multiple pages with header row replay.
|
||||
// The replayed header rows on each continuation page must keep the
|
||||
// exact per-column widths computed for the original table.
|
||||
|
||||
$tableRows = '';
|
||||
for ($i = 1; $i <= 100; ++$i) {
|
||||
$tableRows .=
|
||||
'<tr>'
|
||||
. '<td style="border-bottom: 1px solid red;">'
|
||||
. $i
|
||||
. '</td>'
|
||||
. '<td style="color:rgba(0, 170, 255, 0.4); border-bottom: 1px solid red; ">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</td>'
|
||||
. '<td style="text-align:right">'
|
||||
. \number_format($i * 12.34, 2)
|
||||
. '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
|
||||
$tablehtml =
|
||||
'<h2>Table across pages (px unit)</h2>'
|
||||
. '<style> .UNUSED { color:red; } </style>'
|
||||
. '<table border="1" cellpadding="3" cellspacing="0">'
|
||||
. '<thead>'
|
||||
. '<tr style="background-color:#cccccc">'
|
||||
. '<th>#</th><th>Description</th><th>Amount</th>'
|
||||
. '</tr>'
|
||||
. '</thead>'
|
||||
. $tableRows
|
||||
. '</table>';
|
||||
|
||||
$pdf->addHTMLCell(html: $tablehtml, posx: 20, posy: 20, width: 360);
|
||||
|
||||
// =============================================================
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E078_htmlcell_page_margins.php
|
||||
*
|
||||
* @since 2026-06-14
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
//
|
||||
// A single A4 page is created with 100mm top and bottom margins, leaving a
|
||||
// narrow central content band. getHTMLCell() returns the PDF code for an HTML
|
||||
// block at absolute page coordinates, so HTML text can be placed in the top
|
||||
// margin (border), in the central content area, and in the bottom margin
|
||||
// (border) of the same page.
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 078');
|
||||
$pdf->setTitle('addHTMLCell in Page Margins');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf html addHTMLCell margin border top bottom center absolute');
|
||||
$pdf->setPDFFilename('078_htmlcell_page_margins.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
// ----------
|
||||
|
||||
// Top and bottom margins (mm).
|
||||
$topMargin = 100.0;
|
||||
$bottomMargin = 100.0;
|
||||
|
||||
// Insert font.
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
|
||||
// Add a single A4 page with 100mm top and bottom margins.
|
||||
// 'autobreak' is disabled so placing content in the bottom margin does not
|
||||
// trigger an automatic page break and everything stays on one page.
|
||||
$page = $pdf->addPage([
|
||||
'format' => 'A4',
|
||||
'orientation' => 'P',
|
||||
'autobreak' => false,
|
||||
'margin' => [
|
||||
'PT' => $topMargin,
|
||||
'PB' => $bottomMargin,
|
||||
'CT' => $topMargin,
|
||||
'CB' => $bottomMargin,
|
||||
],
|
||||
]);
|
||||
|
||||
// Add font to the page.
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$pageWidth = (float) $page['width'];
|
||||
$pageHeight = (float) $page['height'];
|
||||
$contentTop = $topMargin;
|
||||
$contentBottom = $pageHeight - $bottomMargin;
|
||||
|
||||
// ----------
|
||||
|
||||
// Draw the two margin boundary lines so the top/bottom borders are visible.
|
||||
$lineStyle = [
|
||||
'lineWidth' => 0.3,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [2, 2],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'red',
|
||||
];
|
||||
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, $contentTop, $pageWidth, $contentTop, $lineStyle));
|
||||
$pdf->page->addContent($pdf->graph->getLine(0, $contentBottom, $pageWidth, $contentBottom, $lineStyle));
|
||||
|
||||
// ----------
|
||||
|
||||
// Horizontal placement of the HTML cells (centered with 20mm side gaps).
|
||||
$cellX = 20.0;
|
||||
$cellW = $pageWidth - (2 * $cellX);
|
||||
|
||||
// An explicit cell height is passed so each block is treated as an
|
||||
// absolutely-positioned bounded box. Without it, content placed below the
|
||||
// content region (e.g. the bottom margin) is treated as overflow and the
|
||||
// HTML cursor is reset to the top of the content area.
|
||||
$cellH = 20.0;
|
||||
|
||||
// 1) Text in the TOP border (inside the top margin area).
|
||||
$pdf->page->addContent($pdf->getHTMLCell(
|
||||
html: '<div style="text-align:center; color:#008000;">'
|
||||
. '<p><b>TOP BORDER</b><br />This text is placed inside the 100mm top margin.</p>'
|
||||
. '<table border="1"><tr><td>Table Cell TOP</td></tr></table>'
|
||||
. '</div>',
|
||||
posx: $cellX,
|
||||
posy: ($topMargin / 2) - 10,
|
||||
width: $cellW,
|
||||
height: $cellH,
|
||||
));
|
||||
|
||||
// 2) Text in the CENTRAL content area.
|
||||
$pdf->page->addContent($pdf->getHTMLCell(
|
||||
html: '<div style="text-align:center; color:#000080;">'
|
||||
. '<p><b>CENTRAL PAGE</b><br />This text is placed in the central content area '
|
||||
. 'between the top and bottom margins.</p>'
|
||||
. '<table border="1"><tr><td>Table Cell CENTRAL</td></tr></table>'
|
||||
. '</div>',
|
||||
posx: $cellX,
|
||||
posy: (($contentTop + $contentBottom) / 2) - 10,
|
||||
width: $cellW,
|
||||
height: $cellH,
|
||||
));
|
||||
|
||||
// 3) Text in the BOTTOM border (inside the bottom margin area).
|
||||
$pdf->page->addContent($pdf->getHTMLCell(
|
||||
html: '<div style="text-align:center; color:#800000;">'
|
||||
. '<p><b>BOTTOM BORDER</b><br />This text is placed inside the 100mm bottom margin.</p>'
|
||||
. '<table border="1"><tr><td>Table Cell BOTTOM</td></tr></table>'
|
||||
. '</div>',
|
||||
posx: $cellX,
|
||||
posy: $contentBottom + ($bottomMargin / 2) - 10,
|
||||
width: $cellW,
|
||||
height: $cellH,
|
||||
));
|
||||
|
||||
// ----------
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__).'/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E079_font_stretch_spacing_matrix.php
|
||||
*
|
||||
* @since 2026-06-15
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// This example exercises horizontal font stretching (Tz) and
|
||||
// character spacing (Tc) through both the direct text API (Section 1) and the
|
||||
// HTML/CSS engine (Section 2), across every combination of alignment,
|
||||
// stretching and spacing for two fonts (times and dejavuserif).
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 079');
|
||||
$pdf->setTitle('Font stretching and spacing matrix');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example font stretch Tz spacing Tc letter-spacing font-stretch html css');
|
||||
$pdf->setPDFFilename('079_font_stretch_spacing_matrix.pdf');
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
// ---------- shared layout constants ----------
|
||||
|
||||
$marginLeft = 15.0;
|
||||
$contentWidth = 180.0;
|
||||
$topY = 15.0;
|
||||
$bottomLimit = 285.0;
|
||||
$rowHeight = 8.0;
|
||||
|
||||
$boxStyle = [
|
||||
'all' => [
|
||||
'lineWidth' => 0.2,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'gray',
|
||||
'fillColor' => '',
|
||||
],
|
||||
];
|
||||
|
||||
// Matrix dimensions (mirror example_063: 90/100/110% and -0.254/0/+0.254mm).
|
||||
$alignments = ['L' => 'LEFT', 'C' => 'CENTER', 'R' => 'RIGHT', 'J' => 'JUSTIFY'];
|
||||
$cssAlign = ['L' => 'left', 'C' => 'center', 'R' => 'right', 'J' => 'justify'];
|
||||
$stretchRatios = [0.90, 1.00, 1.10]; // font-stack stretching ratios (1.0 = 100%)
|
||||
$spacingPoints = [-0.72, 0.0, 0.72]; // direct API character spacing (points)
|
||||
$spacingMillim = [-0.254, 0.0, 0.254]; // CSS letter-spacing (mm); ~ the spacing above
|
||||
$fonts = ['times', 'dejavuserif'];
|
||||
|
||||
// ---------- helpers ----------
|
||||
|
||||
$setFont = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
string $family,
|
||||
string $style,
|
||||
float $size,
|
||||
float $spacing = 0.0,
|
||||
float $stretching = 1.0,
|
||||
): void {
|
||||
$font = $pdf->font->insert($pdf->pon, $family, $style, $size, $spacing, $stretching);
|
||||
$pdf->page->addContent($font['out']);
|
||||
};
|
||||
|
||||
// Register a neutral current font without writing to any page; used before
|
||||
// addPage() so the new page is created with a valid current font.
|
||||
$ensureFont = static function (\Com\Tecnick\Pdf\Tcpdf $pdf): void {
|
||||
$pdf->font->insert($pdf->pon, 'helvetica', '', 10, 0.0, 1.0);
|
||||
};
|
||||
|
||||
$heading = static function (
|
||||
\Com\Tecnick\Pdf\Tcpdf $pdf,
|
||||
string $title,
|
||||
string $subtitle,
|
||||
float $marginLeft,
|
||||
float $contentWidth,
|
||||
float $y,
|
||||
) use ($setFont): float {
|
||||
$setFont($pdf, 'helvetica', 'B', 13);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $title,
|
||||
posx: $marginLeft,
|
||||
posy: $y,
|
||||
width: $contentWidth,
|
||||
height: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
$setFont($pdf, 'helvetica', '', 9);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $subtitle,
|
||||
posx: $marginLeft,
|
||||
posy: $y + 6.5,
|
||||
width: $contentWidth,
|
||||
height: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
));
|
||||
|
||||
return $y + 15.0;
|
||||
};
|
||||
|
||||
// ========== SECTION 1 — DIRECT TEXT API ==========
|
||||
|
||||
foreach ($fonts as $family) {
|
||||
$ensureFont($pdf); // ensure a current font exists before addPage
|
||||
$pdf->addPage();
|
||||
$y = $heading(
|
||||
$pdf,
|
||||
'Example 079 - Section 1: direct text API (font: ' . $family . ')',
|
||||
'Each row inserts the font with a stretching ratio and character spacing, then renders the '
|
||||
. 'label via getTextCell() using the L/C/R/J alignment shown.',
|
||||
$marginLeft,
|
||||
$contentWidth,
|
||||
$topY,
|
||||
);
|
||||
|
||||
foreach ($alignments as $code => $name) {
|
||||
foreach ($stretchRatios as $ratio) {
|
||||
foreach ($spacingPoints as $spacing) {
|
||||
if (($y + $rowHeight) > $bottomLimit) {
|
||||
$ensureFont($pdf);
|
||||
$pdf->addPage();
|
||||
$y = $topY;
|
||||
}
|
||||
|
||||
$setFont($pdf, $family, '', 14, $spacing, $ratio);
|
||||
$pdf->page->addContent($pdf->graph->getRect(
|
||||
$marginLeft,
|
||||
$y,
|
||||
$contentWidth,
|
||||
$rowHeight,
|
||||
'D',
|
||||
$boxStyle,
|
||||
));
|
||||
$label = \sprintf(
|
||||
'%s | Stretching = %d%% | Spacing = %+.3fpt',
|
||||
$name,
|
||||
(int) \round($ratio * 100.0),
|
||||
$spacing,
|
||||
);
|
||||
$pdf->page->addContent($pdf->getTextCell(
|
||||
txt: $label,
|
||||
posx: $marginLeft,
|
||||
posy: $y,
|
||||
width: $contentWidth,
|
||||
height: $rowHeight,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: $code,
|
||||
drawcell: false,
|
||||
));
|
||||
$y += $rowHeight + 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
$y += 1.5; // gap between alignment groups
|
||||
}
|
||||
}
|
||||
|
||||
// ========== SECTION 2 — HTML / CSS API ==========
|
||||
|
||||
foreach ($fonts as $family) {
|
||||
$ensureFont($pdf); // ensure a current font exists before addPage
|
||||
$pdf->addPage();
|
||||
$y = $heading(
|
||||
$pdf,
|
||||
'Example 079 - Section 2: HTML/CSS API (font: ' . $family . ')',
|
||||
'Each bordered block is an HTML span carrying CSS font-stretch and letter-spacing; the '
|
||||
. 'wrapping paragraph must stay inside its cell with the stretch/spacing applied.',
|
||||
$marginLeft,
|
||||
$contentWidth,
|
||||
$topY,
|
||||
);
|
||||
|
||||
// Base font for the HTML engine (neutral stretch/spacing root).
|
||||
$setFont($pdf, $family, '', 11);
|
||||
|
||||
$html = '';
|
||||
foreach ($alignments as $code => $name) {
|
||||
foreach ($stretchRatios as $ratio) {
|
||||
$pct = (int) \round($ratio * 100.0);
|
||||
foreach ($spacingMillim as $spacing) {
|
||||
$html .=
|
||||
'<table border="1" cellpadding="3" cellspacing="0" style="width:100%;"><tr><td>'
|
||||
. '<div style="text-align:'
|
||||
. $cssAlign[$code]
|
||||
. ';">'
|
||||
. '<span style="font-stretch:'
|
||||
. $pct
|
||||
. '%;letter-spacing:'
|
||||
. $spacing
|
||||
. 'mm;">'
|
||||
. '<span style="color:red;">'
|
||||
. $name
|
||||
. '</span> | '
|
||||
. '<span style="color:green;">Stretching = '
|
||||
. $pct
|
||||
. '%</span> | '
|
||||
. '<span style="color:blue;">Spacing = '
|
||||
. \sprintf('%+.3F', $spacing)
|
||||
. 'mm</span><br />'
|
||||
. 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sed imperdiet lectus. '
|
||||
. 'Phasellus quis velit velit, non condimentum quam. Sed neque urna, ultrices ac '
|
||||
. 'volutpat vel, laoreet vitae augue. Sed vel velit erat. Class aptent taciti sociosqu '
|
||||
. 'ad litora torquent per conubia nostra, per inceptos himenaeos.'
|
||||
. '</span></div></td></tr></table>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pdf->addHTMLCell(html: $html, posx: $marginLeft, posy: $y, width: $contentWidth, height: 0);
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
// get PDF document as raw string
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
// Various output modes:
|
||||
|
||||
//$pdf->savePDF(\dirname(__DIR__) . '/target', $rawpdf);
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
|
||||
//$pdf->downloadPDF($rawpdf);
|
||||
//echo $pdf->getMIMEAttachmentPDF($rawpdf);
|
||||
@@ -0,0 +1,377 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E080_no_write_regions.php
|
||||
*
|
||||
* @since 2026-06-16
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*
|
||||
* No-write page regions (legacy TCPDF example_064 equivalent).
|
||||
*
|
||||
* A no-write region is a portion of the page that flowing text will avoid. Each region is
|
||||
* defined exactly as in the legacy library: a vertical, possibly slanted, segment plus the
|
||||
* page side it blocks ('L' or 'R'). tc-lib-pdf-page approximates the resulting writable area
|
||||
* with a stack of rectangular regions (one per horizontal band), so text flows down the page
|
||||
* hugging the obstacle. Several adjacent segments approximate curved shapes (see the circle on
|
||||
* the second scenario). See Com\Tecnick\Pdf\Page\Region::setNoWriteRegions().
|
||||
*
|
||||
* Each obstacle scenario is rendered twice, on consecutive pages, so the two text engines can be
|
||||
* compared side by side:
|
||||
* - with addTextCell() (plain flowing text);
|
||||
* - with addHTMLCell() (HTML cell), producing the SAME visual result.
|
||||
* Both engines hug the rectangular, trapezoidal and circular obstacles band by band and, when
|
||||
* the text overflows the last region, continue on a fresh full-width page (no-write regions are
|
||||
* page-specific, so the continuation page has no obstacles).
|
||||
*
|
||||
* NOTE: the band height must be at least one text line tall; with a 12pt font (~4.9mm line
|
||||
* height) a 5mm band fits exactly one line, giving the finest (per-line) staircase.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// autoloader when using RPM or DEB package installation
|
||||
//require ('/usr/share/php/Com/Tecnick/Pdf/autoload.php');
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
|
||||
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
|
||||
isunicode: true,
|
||||
subsetfont: false,
|
||||
compress: true,
|
||||
mode: \Com\Tecnick\Pdf\PdfConformance::None,
|
||||
objEncrypt: null,
|
||||
);
|
||||
|
||||
// ----------
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 080');
|
||||
$pdf->setTitle('No-write page regions');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example no-write page regions wrap text shape');
|
||||
$pdf->setPDFFilename('080_no_write_regions.pdf');
|
||||
|
||||
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
|
||||
|
||||
// ----------
|
||||
// Fonts (matching legacy example_064: 12pt body, small 8pt annotation labels).
|
||||
// NOTE: the font engine keeps the LAST inserted font as the current one, so each font is
|
||||
// (re)inserted with insertFont() right before it is used, making it the active font.
|
||||
|
||||
$insertFont = static function (string $style, float $size) use ($pdf): void {
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', $style, $size);
|
||||
$pdf->page->addContent($font['out']);
|
||||
};
|
||||
|
||||
// ----------
|
||||
// Colours (matching legacy example_064).
|
||||
|
||||
$black = $pdf->color->getPdfColor('rgb(0,0,0)'); // titles and labels (single-line, no page break)
|
||||
$bodyBlue = 'rgb(0,0,255)'; // flowing body text (justified, as in example_064)
|
||||
|
||||
// Graphic styles: light-green fill, the no-write edge in red, the other edges in grey dashed.
|
||||
$fillStyle = [
|
||||
'lineWidth' => 0.254,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [1, 1],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'rgb(127,127,127)',
|
||||
'fillColor' => 'rgb(220,255,220)',
|
||||
];
|
||||
$edgeGrey = [
|
||||
'lineWidth' => 0.254,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [1, 1],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'rgb(127,127,127)',
|
||||
];
|
||||
$edgeRed = [
|
||||
'lineWidth' => 0.254,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'rgb(255,0,0)',
|
||||
];
|
||||
$arrowStyle = [
|
||||
'lineWidth' => 0.254,
|
||||
'lineCap' => 'butt',
|
||||
'lineJoin' => 'miter',
|
||||
'dashArray' => [],
|
||||
'dashPhase' => 0,
|
||||
'lineColor' => 'rgb(0,0,0)',
|
||||
];
|
||||
|
||||
// Image used as a rectangular obstacle (legacy example used images/image_demo.jpg).
|
||||
$imgFile = \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-image/test/images/200x100_RGBICC.jpg');
|
||||
$imgId = $pdf->image->add($imgFile);
|
||||
|
||||
// Flowing body text (kept blue and justified as in example_064).
|
||||
$intro =
|
||||
'TEST PAGE REGIONS: a no-write region is a portion of the page with a rectangular or '
|
||||
. 'trapezium shape that will not be covered when writing text. A region is aligned on the '
|
||||
. 'left or right side of the page and is defined using a vertical segment. You can set '
|
||||
. 'multiple regions for the same page, and combine several adjacent regions to approximate '
|
||||
. 'curved shapes.';
|
||||
|
||||
$lorem =
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sed imperdiet lectus. Phasellus '
|
||||
. 'quis velit velit, non condimentum quam. Sed neque urna, ultrices ac volutpat vel, laoreet '
|
||||
. 'vitae augue. Sed vel velit erat. Class aptent taciti sociosqu ad litora torquent per conubia '
|
||||
. 'nostra, per inceptos himenaeos. Cras eget velit nulla, eu sagittis elit. Nunc ac arcu est, in '
|
||||
. 'lobortis tellus. Praesent condimentum rhoncus sodales. In hac habitasse platea dictumst. Proin '
|
||||
. 'porta eros pharetra enim tincidunt dignissim nec vel dolor. Cras sapien elit, ornare ac '
|
||||
. 'dignissim eu, ultricies ac eros. Maecenas augue magna, ultrices a congue in, mollis eu nulla. '
|
||||
. 'Nunc venenatis massa at est eleifend faucibus. Vivamus sed risus lectus, nec interdum nunc. '
|
||||
. 'Fusce et felis vitae diam lobortis sollicitudin. Aenean tincidunt accumsan nisi, id vehicula '
|
||||
. 'quam laoreet elementum. Phasellus egestas interdum erat, et viverra ipsum ultricies ac.';
|
||||
|
||||
// More text than fits on a no-write page: with automatic page break enabled the flow continues
|
||||
// on a fresh page. No-write regions are page-specific, so that continuation page has no
|
||||
// obstacles and the text returns to the full page width.
|
||||
$body = $intro . ' ' . \str_repeat($lorem . ' ', 5);
|
||||
|
||||
$margin = [
|
||||
'PL' => 15.0,
|
||||
'PR' => 15.0,
|
||||
'CT' => 25.0,
|
||||
'CB' => 12.0,
|
||||
];
|
||||
$bandHeight = 5.0;
|
||||
|
||||
// =============================================================
|
||||
// Reusable building blocks, so each obstacle scenario can be rendered identically with the
|
||||
// plain-text engine (addTextCell) and the HTML engine (addHTMLCell).
|
||||
|
||||
// Add a page and print its (black) title.
|
||||
$startPage = static function (string $title) use ($pdf, $margin, $black, $insertFont): array {
|
||||
$page = $pdf->addPage(['margin' => $margin]);
|
||||
$pdf->page->addContent($black);
|
||||
$insertFont('B', 13);
|
||||
$pdf->addTextCellXY(txt: $title, posx: 15, posy: 12, drawcell: false);
|
||||
|
||||
return $page;
|
||||
};
|
||||
|
||||
// Draw the two image obstacles plus the two trapezoids (with xt,yt / xb,yb / side labels and
|
||||
// direction arrows, as in the legacy example) and register the matching no-write regions.
|
||||
$setupTrapezoids = static function (float $pageHeight) use (
|
||||
$pdf,
|
||||
$imgId,
|
||||
$fillStyle,
|
||||
$edgeGrey,
|
||||
$edgeRed,
|
||||
$arrowStyle,
|
||||
$black,
|
||||
$insertFont,
|
||||
$bandHeight,
|
||||
): void {
|
||||
// Two image obstacles: top-right and bottom-left.
|
||||
$pdf->page->addContent($pdf->image->getSetImage($imgId, 155, 30, 40, 40, $pageHeight));
|
||||
$pdf->page->addContent($pdf->image->getSetImage($imgId, 15, 230, 40, 40, $pageHeight));
|
||||
|
||||
// Left trapezoid: the slanted right edge (57,90)-(67,140) is the no-write boundary (red).
|
||||
$pdf->page->addContent($pdf->graph->getPolygon([15, 90, 57, 90, 67, 140, 15, 140, 15, 90], 'DF', [
|
||||
'all' => $fillStyle,
|
||||
0 => $edgeGrey,
|
||||
1 => $edgeRed,
|
||||
2 => $edgeGrey,
|
||||
3 => $edgeGrey,
|
||||
]));
|
||||
|
||||
// Right trapezoid: the slanted left edge (155,180)-(145,130) is the no-write boundary (red).
|
||||
$pdf->page->addContent($pdf->graph->getPolygon([145, 130, 195, 130, 195, 180, 155, 180, 145, 130], 'DF', [
|
||||
'all' => $fillStyle,
|
||||
0 => $edgeGrey,
|
||||
1 => $edgeGrey,
|
||||
2 => $edgeGrey,
|
||||
3 => $edgeRed,
|
||||
]));
|
||||
|
||||
// Annotation labels and direction arrows (8pt black), as in the legacy example.
|
||||
$pdf->page->addContent($black);
|
||||
$insertFont('', 8);
|
||||
$pdf->addTextCellXY(
|
||||
txt: 'xt,yt',
|
||||
posx: 38,
|
||||
posy: 90,
|
||||
width: 18,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->addTextCellXY(
|
||||
txt: 'xb,yb',
|
||||
posx: 48,
|
||||
posy: 136,
|
||||
width: 18,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->addTextCellXY(
|
||||
txt: 'side',
|
||||
posx: 38,
|
||||
posy: 111,
|
||||
width: 16,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Right,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->page->addContent($pdf->graph->getArrow(60, 115, 40, 115, 2, 4, 15, $arrowStyle));
|
||||
|
||||
$pdf->addTextCellXY(
|
||||
txt: 'xt,yt',
|
||||
posx: 147,
|
||||
posy: 130,
|
||||
width: 18,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->addTextCellXY(
|
||||
txt: 'xb,yb',
|
||||
posx: 156,
|
||||
posy: 176,
|
||||
width: 18,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->addTextCellXY(
|
||||
txt: 'side',
|
||||
posx: 158,
|
||||
posy: 151,
|
||||
width: 16,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
drawcell: false,
|
||||
);
|
||||
$pdf->page->addContent($pdf->graph->getArrow(152, 155, 172, 155, 2, 4, 15, $arrowStyle));
|
||||
|
||||
// No-write regions: each is a segment (xt,yt)-(xb,yb) plus the blocked page side.
|
||||
$pdf->page->setNoWriteRegions(
|
||||
[
|
||||
['xt' => 153, 'yt' => 30, 'xb' => 153, 'yb' => 70, 'side' => 'R'], // top-right image
|
||||
['xt' => 60, 'yt' => 90, 'xb' => 70, 'yb' => 140, 'side' => 'L'], // left trapezoid
|
||||
['xt' => 143, 'yt' => 130, 'xb' => 153, 'yb' => 180, 'side' => 'R'], // right trapezoid
|
||||
['xt' => 58, 'yt' => 230, 'xb' => 58, 'yb' => 270, 'side' => 'L'], // bottom-left image
|
||||
],
|
||||
$bandHeight,
|
||||
);
|
||||
};
|
||||
|
||||
// Draw the circular obstacle (left half-disc against the right content edge) traced by eight
|
||||
// adjacent right-side segments, and register the matching no-write regions.
|
||||
$setupCircle = static function () use ($pdf, $fillStyle, $bandHeight): void {
|
||||
$pdf->page->addContent($pdf->graph->getPolygon(
|
||||
[
|
||||
195,
|
||||
110,
|
||||
179.693,
|
||||
113.045,
|
||||
166.716,
|
||||
121.716,
|
||||
158.045,
|
||||
134.693,
|
||||
155,
|
||||
150,
|
||||
158.045,
|
||||
165.307,
|
||||
166.716,
|
||||
178.284,
|
||||
179.693,
|
||||
186.955,
|
||||
195,
|
||||
190,
|
||||
],
|
||||
'DF',
|
||||
['all' => $fillStyle],
|
||||
));
|
||||
|
||||
$pdf->page->setNoWriteRegions([
|
||||
['xt' => 195, 'yt' => 110, 'xb' => 179.693, 'yb' => 113.045, 'side' => 'R'],
|
||||
['xt' => 179.693, 'yt' => 113.045, 'xb' => 166.716, 'yb' => 121.716, 'side' => 'R'],
|
||||
['xt' => 166.716, 'yt' => 121.716, 'xb' => 158.045, 'yb' => 134.693, 'side' => 'R'],
|
||||
['xt' => 158.045, 'yt' => 134.693, 'xb' => 155, 'yb' => 150, 'side' => 'R'],
|
||||
['xt' => 155, 'yt' => 150, 'xb' => 158.045, 'yb' => 165.307, 'side' => 'R'],
|
||||
['xt' => 158.045, 'yt' => 165.307, 'xb' => 166.716, 'yb' => 178.284, 'side' => 'R'],
|
||||
['xt' => 166.716, 'yt' => 178.284, 'xb' => 179.693, 'yb' => 186.955, 'side' => 'R'],
|
||||
['xt' => 179.693, 'yt' => 186.955, 'xb' => 195, 'yb' => 190, 'side' => 'R'],
|
||||
], $bandHeight);
|
||||
};
|
||||
|
||||
// Flow the body with the plain-text engine. width 0 makes each band use its own writable width.
|
||||
// The fill colour is set through the graph so it is tracked and re-applied automatically when the
|
||||
// flow continues on an automatically added page (the colour resets per page).
|
||||
$renderTextBody = static function () use ($pdf, $body, $bodyBlue, $insertFont): void {
|
||||
$pdf->page->addContent($pdf->graph->add(['fillColor' => $bodyBlue]));
|
||||
$insertFont('', 12);
|
||||
$pdf->addTextCell(
|
||||
txt: $body,
|
||||
posx: 0,
|
||||
posy: 0,
|
||||
width: 0,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Justify,
|
||||
drawcell: false,
|
||||
);
|
||||
};
|
||||
|
||||
// Flow the SAME body with the HTML engine. A single justified, coloured paragraph hugs the
|
||||
// obstacle band by band exactly like addTextCell, and overflows onto a fresh full-width page.
|
||||
// A font must be active before addHTMLCell(). getHTMLCell() returns the same rendering as a
|
||||
// string instead of emitting it (e.g. $code = $pdf->getHTMLCell(...); $pdf->page->addContent($code);).
|
||||
$renderHtmlBody = static function () use ($pdf, $body, $bodyBlue, $insertFont): void {
|
||||
$insertFont('', 12);
|
||||
$region = $pdf->page->getRegion();
|
||||
$html = '<p style="text-align:justify;color:' . $bodyBlue . ';">' . $body . '</p>';
|
||||
$pdf->addHTMLCell(
|
||||
html: $html,
|
||||
posx: (float) $region['RX'],
|
||||
posy: (float) $region['RY'],
|
||||
width: (float) $region['RW'],
|
||||
);
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// SCENARIO 1: rectangular and trapezoidal no-write regions around two images.
|
||||
|
||||
$page = $startPage('No-write page regions: addTextCell flowing around rectangular and trapezoidal shapes');
|
||||
$pageHeight = (float) $page['height'];
|
||||
$setupTrapezoids($pageHeight);
|
||||
$renderTextBody();
|
||||
|
||||
$startPage('No-write page regions: addHTMLCell flowing around rectangular and trapezoidal shapes');
|
||||
$setupTrapezoids($pageHeight);
|
||||
$renderHtmlBody();
|
||||
|
||||
// =============================================================
|
||||
// SCENARIO 2: eight adjacent regions approximating a circle (text wraps its left side).
|
||||
|
||||
$startPage('No-write page regions: addTextCell flowing around a circular shape (8 adjacent segments)');
|
||||
$setupCircle();
|
||||
$renderTextBody();
|
||||
|
||||
$startPage('No-write page regions: addHTMLCell flowing around a circular shape (8 adjacent segments)');
|
||||
$setupCircle();
|
||||
$renderHtmlBody();
|
||||
|
||||
// =============================================================
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* E081_signature_pades_lta.php
|
||||
*
|
||||
* @since 2026-07-15
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
|
||||
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
|
||||
// trusted paths that covers this package tree, so run the examples in place. To read assets
|
||||
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
|
||||
// parameter (see E047_remote_resources_security.php).
|
||||
|
||||
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
|
||||
|
||||
// autoloader when using Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// define fonts directory
|
||||
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
// main TCPDF object
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf();
|
||||
|
||||
$pdf->setCreator('tc-lib-pdf');
|
||||
$pdf->setAuthor('Nicola Asuni');
|
||||
$pdf->setSubject('tc-lib-pdf example: 081');
|
||||
$pdf->setTitle('PAdES B-LTA Archive Timestamp Signature Example');
|
||||
$pdf->setKeywords('TCPDF tc-lib-pdf example signature pades pades-b-lta archive timestamp doctimestamp dss');
|
||||
$pdf->setPDFFilename('081_signature_pades_lta.pdf');
|
||||
|
||||
// Insert font before adding the first page.
|
||||
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
|
||||
|
||||
$page = $pdf->addPage();
|
||||
$pdf->page->addContent($bfont['out']);
|
||||
|
||||
$text = 'This document is a PAdES-BASELINE-LTA signature: B-LT plus a document archive timestamp.';
|
||||
$textCell = $pdf->getTextCell(
|
||||
txt: $text,
|
||||
posx: 15,
|
||||
posy: 20,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell);
|
||||
|
||||
$text2 =
|
||||
'The archive timestamp is a /Type /DocTimeStamp field (/SubFilter /ETSI.RFC3161) covering the '
|
||||
. 'whole document, added in a further incremental revision to protect the signature over the long term.';
|
||||
$textCell2 = $pdf->getTextCell(
|
||||
txt: $text2,
|
||||
posx: 15,
|
||||
posy: 27,
|
||||
width: 180,
|
||||
height: 0,
|
||||
offset: 0,
|
||||
linespace: 1,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Top,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
);
|
||||
$pdf->page->addContent($textCell2);
|
||||
|
||||
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
|
||||
if ($certPath === false) {
|
||||
throw new \RuntimeException('Missing signing certificate: examples/data/cert/tcpdf.crt');
|
||||
}
|
||||
|
||||
$cert = 'file://' . $certPath;
|
||||
|
||||
// PAdES-BASELINE-LTA is produced by configuring a B-LT signature (with a TSA) and
|
||||
// then calling upgradeToLta(), which selects the pades-b-lta profile and forces the
|
||||
// LTV material on. The signing process and this demo's limitations are rendered
|
||||
// into the document itself (see the explanatory block added below).
|
||||
$pdf
|
||||
->signature()
|
||||
->configure([
|
||||
'profile' => 'pades-b-lt',
|
||||
'digest_algorithm' => 'sha256',
|
||||
'cert_type' => 2,
|
||||
'info' => [
|
||||
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
|
||||
'Location' => 'Demo Office',
|
||||
'Name' => 'tc-lib-pdf',
|
||||
'Reason' => 'PAdES-BASELINE-LTA archive-timestamped signature example',
|
||||
],
|
||||
'password' => '',
|
||||
'privkey' => $cert,
|
||||
'signcert' => $cert,
|
||||
'ltv' => [
|
||||
'enabled' => true,
|
||||
'embed_ocsp' => true,
|
||||
'embed_crl' => true,
|
||||
'embed_certs' => true,
|
||||
'include_dss' => true,
|
||||
'include_vri' => true,
|
||||
],
|
||||
])
|
||||
->timestamp([
|
||||
'enabled' => true,
|
||||
// Public demo endpoint. For production use your trusted TSA service.
|
||||
'host' => 'https://freetsa.org/tsr',
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'cert' => '',
|
||||
'hash_algorithm' => 'sha256',
|
||||
'policy_oid' => '',
|
||||
'nonce_enabled' => true,
|
||||
'timeout' => 30,
|
||||
'verify_peer' => true,
|
||||
])
|
||||
->upgradeToLta();
|
||||
|
||||
$pdf->signature()->appearance()->place(posx: 15, posy: 40, width: 90, height: 20, page: -1, name: 'ArchiveSignature');
|
||||
|
||||
// Appearance stream marking the long-term archival intent of the signature.
|
||||
$sigW = 90.0;
|
||||
$sigH = 20.0;
|
||||
$sigTopY = $page['height'] - $sigH;
|
||||
|
||||
$sigAppearance = $bfont['out'];
|
||||
$sigAppearance .= $pdf->color->getPdfColor('rgb(15%,15%,15%)');
|
||||
$sigAppearance .= $pdf->getTextCell(
|
||||
txt: 'PAdES B-LTA Archive Signature',
|
||||
posx: 0,
|
||||
posy: $sigTopY,
|
||||
width: $sigW,
|
||||
height: $sigH,
|
||||
offset: 3.0,
|
||||
linespace: 0,
|
||||
valign: \Com\Tecnick\Pdf\TextVAlign::Center,
|
||||
halign: \Com\Tecnick\Pdf\TextHAlign::Left,
|
||||
cell: null,
|
||||
styles: [
|
||||
'all' => [
|
||||
'fillColor' => 'rgb(93%,93%,98%)',
|
||||
'lineColor' => 'rgb(30%,30%,55%)',
|
||||
'lineWidth' => 1.0,
|
||||
],
|
||||
],
|
||||
strokewidth: 0,
|
||||
wordspacing: 0,
|
||||
leading: 0,
|
||||
rise: 0,
|
||||
jlast: true,
|
||||
fill: true,
|
||||
stroke: false,
|
||||
underline: false,
|
||||
linethrough: false,
|
||||
overline: false,
|
||||
clip: false,
|
||||
drawcell: true,
|
||||
);
|
||||
|
||||
$pdf
|
||||
->signature()
|
||||
->appearance()
|
||||
->stream(stream: $sigAppearance, mode: \Com\Tecnick\Pdf\Signature\SignatureAppearanceMode::Normal);
|
||||
|
||||
// Render the signing process and the demo's limitations into the document so the
|
||||
// output PDF is self-documenting (this text is page content, not part of the
|
||||
// signed appearance stream).
|
||||
$explainHtml = <<<HTML
|
||||
<h2 style="font-size:11pt;color:#1f2a33;">How this PAdES-BASELINE-LTA signature is produced</h2>
|
||||
<p style="font-size:9pt;color:#1f2a33;">Configuring a B-LT signature (with a TSA) and then calling
|
||||
<code>upgradeToLta()</code> selects the pades-b-lta profile and forces the LTV material on, so the output
|
||||
carries three incremental revisions: the CAdES signature with its RFC 3161 signature timestamp (B-T),
|
||||
the DSS/VRI validation material (B-LT), and a <code>/Type /DocTimeStamp</code> archive timestamp
|
||||
(<code>/SubFilter /ETSI.RFC3161</code>) whose messageImprint covers the whole document up to that
|
||||
revision (B-LTA). The archive timestamp protects the signature and its validation material over the long
|
||||
term, even after the signing certificate or its algorithms weaken.</p>
|
||||
<h2 style="font-size:11pt;color:#7a1f1f;">Limitations of this demo</h2>
|
||||
<ul style="font-size:9pt;color:#1f2a33;">
|
||||
<li>Two live RFC 3161 requests are made: one for the signature timestamp and one for the archive
|
||||
timestamp. A configured, reachable TSA is required for both; if the TSA is unreachable or rejects a
|
||||
request the signing step throws a signing exception and no PDF is produced.</li>
|
||||
<li>As in E009, the bundled self-signed demo certificate carries no OCSP/CRL responders, so the DSS
|
||||
embeds only certificates and a validator reports B-T with a DSS and an archive timestamp rather than a
|
||||
full B-LTA. A CA-issued certificate with reachable revocation responders is needed for a full B-LTA
|
||||
verdict.</li>
|
||||
</ul>
|
||||
HTML;
|
||||
$pdf->addHTMLCell(html: $explainHtml, posx: 15, posy: 66, width: 180);
|
||||
|
||||
$rawpdf = $pdf->getOutPDFString();
|
||||
$pdf->renderPDF(rawpdf: $rawpdf);
|
||||
@@ -0,0 +1,49 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDsDCCApigAwIBAgIUbuI6OUsZ98QwWqv34Pedqe0p/8owDQYJKoZIhvcNAQEL
|
||||
BQAwYTELMAkGA1UEBhMCSVQxDTALBgNVBAsMBERFTU8xDjAMBgNVBAoMBVRDUERG
|
||||
MRMwEQYDVQQDDApUQ1BERiBERU1PMR4wHAYJKoZIhvcNAQkBFg95b3VAZXhhbXBs
|
||||
ZS5jb20wHhcNMjYwNzE1MjA0NDE5WhcNMzYwNzEyMjA0NDE5WjBhMQswCQYDVQQG
|
||||
EwJJVDENMAsGA1UECwwEREVNTzEOMAwGA1UECgwFVENQREYxEzARBgNVBAMMClRD
|
||||
UERGIERFTU8xHjAcBgkqhkiG9w0BCQEWD3lvdUBleGFtcGxlLmNvbTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBANIOjRRM5gLaFavAGp5LpWi2RzhOgtkL
|
||||
9VJd06tihV3d34Gdtp2ico2KaQHZge1roFD4B3EJyvxOFL4KA1rvcruPPIw0N2YZ
|
||||
8rxEIlHqS3IVYZj+fnPOP36DTfWnketY2hFScOJZrMOL9F36chXKMX2prDtI3Co7
|
||||
qV/yz0nvilF3zX3r8YrNn9/had3aZIpGYWCyDnePm+pSwd58xfR+l5KA2hkka2Dw
|
||||
eHUDZIvJT78u1+NhbeFBy2Zzu2sBES5W3A6Zbl8IiG8isjo3DYzxe4nUGvma5qAS
|
||||
zqLwauOhMQ5m7MORStBaNUWGouanf6Kt0ZS1kgh9n6SqYlPeFse0FKkCAwEAAaNg
|
||||
MF4wHQYDVR0OBBYEFLjRwjeRSjBuaMePr4fqjC9kADyIMB8GA1UdIwQYMBaAFLjR
|
||||
wjeRSjBuaMePr4fqjC9kADyIMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAA
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQBOtkeXrmjJ1QWq8eRceIh3Rs12y9vSHZpafibi
|
||||
ZTF+Q2j6rytKnqBOABCaiJm3E+jDfsU6vbS0YtJX4q6LAYsjcn1fRiCv6EDq0vXk
|
||||
RUiw3r624v9XFTz4XOegX+Zk8D4b+lWP8erDCokx45U3z3tjKDDjJGjbLZtWzO0h
|
||||
G5TER8EL1jjJm8KpPnV+fwI525IEZr5AN0XNpzz3djnh2XXC/Erm7fmDrDnmtSZf
|
||||
wRjOrT69P/FDTJPmBvZfnYvmnz2W519yUy4PvSZ3Z7IjyronKilHTQujg1EBVJxa
|
||||
z3M2azZ1nkcMcsENk7HVT/YHEUUoHrKJBiLFVgCwB04i208i
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA0g6NFEzmAtoVq8AankulaLZHOE6C2Qv1Ul3Tq2KFXd3fgZ22
|
||||
naJyjYppAdmB7WugUPgHcQnK/E4UvgoDWu9yu488jDQ3ZhnyvEQiUepLchVhmP5+
|
||||
c84/foNN9aeR61jaEVJw4lmsw4v0XfpyFcoxfamsO0jcKjupX/LPSe+KUXfNfevx
|
||||
is2f3+Fp3dpkikZhYLIOd4+b6lLB3nzF9H6XkoDaGSRrYPB4dQNki8lPvy7X42Ft
|
||||
4UHLZnO7awERLlbcDpluXwiIbyKyOjcNjPF7idQa+ZrmoBLOovBq46ExDmbsw5FK
|
||||
0Fo1RYai5qd/oq3RlLWSCH2fpKpiU94Wx7QUqQIDAQABAoIBABVehddrechPPZ5k
|
||||
+whAx5VrGrx1jz3rp6O/GBQiwBDULCNUYzIu5yKzUpqtsRgxR2RJUT98iK4JdvZ8
|
||||
0AnRm31NdXJJcxvT1rP0pf2pnU6AMpc1B7H6CM9S5gzQROnZdojF12ZNi2Py0lO3
|
||||
sWC6WrXPG66Fy2EQA/t2+QPLZsnB/Ah5B+CXfhke3PIrqeukB9p8lZfufHpaWZ1o
|
||||
Yb5IPOhjj8kEgzGTC3E8CFg75hhrXigW88sSvqiy/oJNKKxwqNN2idCXj1uMn65n
|
||||
1GBATCqSHaX9mSJnLg7KVGzZ8dvDGU7vZcf589Xa/P3IvDId6OnmzbFR/vY3TOcI
|
||||
fLGpQIECgYEA/99b1xcM1z9P+JMCkBEYMu0eOtV2NfFSBeePBSCIzfOj6QquxPnh
|
||||
9UHvWwlqFlzDwWoEDZ5zYmDE95uV6qLMlzluRnbjCzuIwa4uo7w7B9HaSxOwXwEm
|
||||
K064kzY5oS1EQIucR+e5cToTeIoKwe5lSPANuxM2oP3E0FcYE9+0xikCgYEA0ilZ
|
||||
A4APQreFiqcLmvYs3xGuU9AE9v3EFQDA921x1l0VsiJyyALlypzZfNvt5CxcbTrQ
|
||||
6dLFW9bztrhDZ8wvBZBD0gCLDVErAqolRIrxXcjP1KBiKVrweq+/UvgY4fDoptAW
|
||||
z9rKii18fgiXFASAP0XoFti4vap2YtsxxkB9qoECgYBQ+Fq0xxuOJf/llofyFSbG
|
||||
PtkZHyHIUjR1n+BXbAM+wUH2ZiYGOVky5ombEnCa4QIle6oKsUCsOhk6jea0GI6L
|
||||
sGXgMJEKpe1R9Q/XSqKXh+X/ahyfA9sTS1cHZtp30b5Oep+a9Y5ucUVmGLDsy8cL
|
||||
fMOrlpnr+kJE97qr11f6eQKBgFH4oqmE1270Wff8s8AbaOEQ6mfyaR1VWZe/lYRs
|
||||
gcxUvlOesBpnVu2yQ/o5Zg5rZxmLqVSqSyRJMQIB2PixYV3QKUPNxm7JS/dcGfEk
|
||||
KISmALo0XFU5DTctOXjJIBtwda4q19r2wa0nlLkr7JF4N/V19NKEcXo49LgWOtHS
|
||||
8bEBAoGBALJTyQICxl32BgiqyUpbbcf70r9AWqR7RsMFNYLcEsaiaTRWQooMiyYg
|
||||
i5JLpASa8Z+MlPReOp0ugaGL5HCVM4MsKTIH9kFx/OriyTFU3bKLvylwGC5sheg+
|
||||
crsLLzlgCpfcz5r8L5xLxLhU7TN5etmUQXLayuHymUU9wd7gXF7G
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,176 @@
|
||||
% hyph-nl-sample.tex — minimal Dutch hyphenation pattern sample
|
||||
%
|
||||
% This is a REDUCED excerpt of the standard Dutch TeX hyphenation patterns
|
||||
% (hyph-nl.tex, originally by Piet Tutelaers, public domain).
|
||||
% It is provided as an example data file for tc-lib-pdf/E064.
|
||||
%
|
||||
% Full patterns are available from:
|
||||
% https://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/tex
|
||||
%
|
||||
% Format: \patterns{ <pattern> ... }
|
||||
% Each pattern is a string of letters optionally interleaved with digits.
|
||||
% A digit k at position i means: if the subword matches, priority k applies
|
||||
% at that break point. Odd priorities allow hyphenation; even priorities prevent it.
|
||||
% The pattern without digits is the lookup key.
|
||||
%
|
||||
\patterns{
|
||||
.on5
|
||||
.ver5
|
||||
aa2
|
||||
2aa
|
||||
ab5
|
||||
2b1r
|
||||
be5
|
||||
co2
|
||||
2co
|
||||
d1w
|
||||
e2l
|
||||
en5
|
||||
2en
|
||||
er5
|
||||
ge5
|
||||
1ge
|
||||
2h1
|
||||
i2n
|
||||
in5
|
||||
2in
|
||||
1ka
|
||||
2k1l
|
||||
k5le
|
||||
2k1n
|
||||
k2o
|
||||
k5om
|
||||
2k1r
|
||||
1la
|
||||
l1a
|
||||
2l1b
|
||||
1le
|
||||
2l1c
|
||||
l2e
|
||||
l2i
|
||||
l2o
|
||||
l2u
|
||||
l2y
|
||||
ma5
|
||||
2m1b
|
||||
2m1m
|
||||
2m1p
|
||||
n2a
|
||||
na5
|
||||
2n1b
|
||||
ne5
|
||||
2n1f
|
||||
n2i
|
||||
ni5
|
||||
2n1k
|
||||
2n1l
|
||||
2n1m
|
||||
2n1n
|
||||
n2o
|
||||
no5
|
||||
2n1p
|
||||
n2u
|
||||
nu5
|
||||
2n1v
|
||||
o2n
|
||||
on5
|
||||
2on
|
||||
oo2
|
||||
2oo
|
||||
or5
|
||||
2or
|
||||
ou5
|
||||
2ou
|
||||
p2a
|
||||
pa5
|
||||
p2e
|
||||
pe5
|
||||
p2i
|
||||
pi5
|
||||
p2o
|
||||
po5
|
||||
2p1r
|
||||
p2u
|
||||
pu5
|
||||
r2a
|
||||
ra5
|
||||
2r1b
|
||||
re5
|
||||
r2i
|
||||
ri5
|
||||
2r1k
|
||||
r2o
|
||||
ro5
|
||||
r2u
|
||||
ru5
|
||||
s2a
|
||||
sa5
|
||||
2s1b
|
||||
se5
|
||||
2s1k
|
||||
s2i
|
||||
si5
|
||||
s2o
|
||||
so5
|
||||
2s1p
|
||||
s2t
|
||||
st5
|
||||
2s1t
|
||||
s2u
|
||||
su5
|
||||
t2a
|
||||
ta5
|
||||
t2e
|
||||
te5
|
||||
t2i
|
||||
ti5
|
||||
t2o
|
||||
to5
|
||||
t2r
|
||||
tr5
|
||||
t2u
|
||||
tu5
|
||||
u2it
|
||||
uit5
|
||||
u2i
|
||||
ui5
|
||||
v2a
|
||||
va5
|
||||
ve5
|
||||
v2e
|
||||
v2i
|
||||
vi5
|
||||
v2o
|
||||
vo5
|
||||
v2r
|
||||
vr5
|
||||
v2u
|
||||
vu5
|
||||
wa5
|
||||
2w1b
|
||||
we5
|
||||
wi5
|
||||
wo5
|
||||
woordvoer5
|
||||
y2
|
||||
z2a
|
||||
za5
|
||||
ze5
|
||||
zi5
|
||||
zo5
|
||||
zu5
|
||||
.oor5
|
||||
.uit5
|
||||
.ver5
|
||||
.be5
|
||||
.ge5
|
||||
.on5
|
||||
1baar
|
||||
1heid
|
||||
1lijk
|
||||
1loos
|
||||
5heid.
|
||||
5baar.
|
||||
5lijk.
|
||||
5loos.
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
Sentences that contain all letters commonly used in a language
|
||||
--------------------------------------------------------------
|
||||
|
||||
This file is UTF-8 encoded.
|
||||
|
||||
Czech (cz)
|
||||
---------
|
||||
|
||||
Příšerně žluťoučký kůň úpěl ďábelské ódy.
|
||||
Hleď, toť přízračný kůň v mátožné póze šíleně úpí.
|
||||
Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů.
|
||||
Loď čeří kýlem tůň obzvlášť v Grónské úžině.
|
||||
Ó, náhlý déšť již zvířil prach a čilá laň teď běží s houfcem gazel k úkrytům.
|
||||
|
||||
Danish (da)
|
||||
---------
|
||||
|
||||
Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen
|
||||
Wolther spillede på xylofon.
|
||||
(= Quiz contestants were eating strawbery with cream while Wolther
|
||||
the circus clown played on xylophone.)
|
||||
|
||||
German (de)
|
||||
-----------
|
||||
|
||||
Falsches Üben von Xylophonmusik quält jeden größeren Zwerg
|
||||
(= Wrongful practicing of xylophone music tortures every larger dwarf)
|
||||
|
||||
Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich
|
||||
(= Twelve boxing fighters hunted Eva across the dike of Sylt)
|
||||
|
||||
Heizölrückstoßabdämpfung
|
||||
(= fuel oil recoil absorber)
|
||||
(jqvwxy missing, but all non-ASCII letters in one word)
|
||||
|
||||
English (en)
|
||||
------------
|
||||
|
||||
The quick brown fox jumps over the lazy dog
|
||||
|
||||
Spanish (es)
|
||||
------------
|
||||
|
||||
El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y
|
||||
frío, añoraba a su querido cachorro.
|
||||
(Contains every letter and every accent, but not every combination
|
||||
of vowel + acute.)
|
||||
|
||||
French (fr)
|
||||
-----------
|
||||
|
||||
Portez ce vieux whisky au juge blond qui fume sur son île intérieure, à
|
||||
côté de l'alcôve ovoïde, où les bûches se consument dans l'âtre, ce
|
||||
qui lui permet de penser à la cænogenèse de l'être dont il est question
|
||||
dans la cause ambiguë entendue à Moÿ, dans un capharnaüm qui,
|
||||
pense-t-il, diminue çà et là la qualité de son œuvre.
|
||||
|
||||
l'île exiguë
|
||||
Où l'obèse jury mûr
|
||||
Fête l'haï volapük,
|
||||
Âne ex aéquo au whist,
|
||||
Ôtez ce vœu déçu.
|
||||
|
||||
Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en
|
||||
canoë au delà des îles, près du mälström où brûlent les novæ.
|
||||
|
||||
Irish Gaelic (ga)
|
||||
-----------------
|
||||
|
||||
D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh
|
||||
|
||||
Hungarian (hu)
|
||||
--------------
|
||||
|
||||
Árvíztűrő tükörfúrógép
|
||||
(= flood-proof mirror-drilling machine, only all non-ASCII letters)
|
||||
|
||||
Icelandic (is)
|
||||
--------------
|
||||
|
||||
Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa
|
||||
|
||||
Sævör grét áðan því úlpan var ónýt
|
||||
(some ASCII letters missing)
|
||||
|
||||
Greek (el)
|
||||
-------------
|
||||
|
||||
Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο
|
||||
(= No more shall I see acacias or myrtles in the golden clearing)
|
||||
|
||||
Ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία
|
||||
(= I uncover the soul-destroying abhorrence)
|
||||
|
||||
Hebrew (iw)
|
||||
-----------
|
||||
|
||||
? דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה
|
||||
|
||||
Polish (pl)
|
||||
-----------
|
||||
|
||||
Pchnąć w tę łódź jeża lub osiem skrzyń fig
|
||||
(= To push a hedgehog or eight bins of figs in this boat)
|
||||
|
||||
Zażółć gęślą jaźń
|
||||
|
||||
Russian (ru)
|
||||
------------
|
||||
|
||||
В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!
|
||||
(= Would a citrus live in the bushes of south? Yes, but only a fake one!)
|
||||
|
||||
Thai (th)
|
||||
---------
|
||||
|
||||
[--------------------------|------------------------]
|
||||
๏ เป็นมนุษย์สุดประเสริฐเลิศคุณค่า กว่าบรรดาฝูงสัตว์เดรัจฉาน
|
||||
จงฝ่าฟันพัฒนาวิชาการ อย่าล้างผลาญฤๅเข่นฆ่าบีฑาใคร
|
||||
ไม่ถือโทษโกรธแช่งซัดฮึดฮัดด่า หัดอภัยเหมือนกีฬาอัชฌาสัย
|
||||
ปฏิบัติประพฤติกฎกำหนดใจ พูดจาให้จ๊ะๆ จ๋าๆ น่าฟังเอย ฯ
|
||||
|
||||
[The copyright for the Thai example is owned by The Computer
|
||||
Association of Thailand under the Royal Patronage of His Majesty the
|
||||
King.]
|
||||
|
||||
Please let me know if you find others! Special thanks to the people
|
||||
from all over the world who contributed these sentences.
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1">
|
||||
<title>Abstract A4 SVG Feature Showcase</title>
|
||||
<desc>Conservative full-page SVG sample for tc-lib-pdf visual inspection.</desc>
|
||||
|
||||
<defs>
|
||||
<linearGradient id="sky" x1="0" y1="0" x2="0" y2="297" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d9ecff"/>
|
||||
<stop offset="1" stop-color="#fff0d9"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="band" x1="20" y1="0" x2="190" y2="0" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ff9b54"/>
|
||||
<stop offset="1" stop-color="#d6457b"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="disc" cx="148" cy="54" r="30" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ffffff"/>
|
||||
<stop offset="1" stop-color="#61b5ff"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
<rect x="0" y="0" width="210" height="297" fill="url(#sky)"/>
|
||||
<rect x="8" y="8" width="194" height="281" fill="none" stroke="#18486b" stroke-width="1"/>
|
||||
|
||||
<polygon points="0,108 90,36 210,72 210,130 94,156" fill="#133b63" fill-opacity="0.9"/>
|
||||
<polygon points="0,150 84,124 210,162 210,220 60,208" fill="#2c6aa0" fill-opacity="0.7"/>
|
||||
<polygon points="0,208 58,202 210,236 210,297 0,297" fill="#0f2e4f" fill-opacity="0.88"/>
|
||||
|
||||
<rect x="22" y="30" width="112" height="22" rx="3" ry="3" fill="url(#band)" stroke="#173d60" stroke-width="0.8"/>
|
||||
<line x1="22" y1="64" x2="188" y2="64" stroke="#18486b" stroke-width="1.2" stroke-dasharray="3 2"/>
|
||||
<line x1="22" y1="71" x2="188" y2="71" stroke="#ff7f50" stroke-width="2"/>
|
||||
|
||||
<circle cx="148" cy="54" r="30" fill="url(#disc)" stroke="#ffffff" stroke-width="2"/>
|
||||
<circle cx="148" cy="54" r="12" fill="none" stroke="#18486b" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<ellipse cx="52" cy="88" rx="24" ry="12" fill="#ffffff" fill-opacity="0.6" stroke="#18486b" stroke-width="1"/>
|
||||
|
||||
<path d="M24,116 C52,92 88,90 122,108 C146,120 170,122 188,114 L188,138 C162,148 136,146 108,134 C78,122 50,122 24,144 Z"
|
||||
fill="#ffffff"
|
||||
fill-opacity="0.75"
|
||||
stroke="#18486b"
|
||||
stroke-width="1.2"/>
|
||||
|
||||
<path d="M26,160 C58,144 96,146 130,166 C152,178 172,180 188,174"
|
||||
fill="none"
|
||||
stroke="#ffd166"
|
||||
stroke-width="4"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
<polyline points="24,174 48,166 70,182 94,160 122,178 148,156 184,174"
|
||||
fill="none"
|
||||
stroke="#ff8c69"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
|
||||
<rect x="28" y="194" width="54" height="54" fill="#f7fbff" stroke="#18486b" stroke-width="1.1" transform="rotate(-8 55 221)"/>
|
||||
<rect x="36" y="204" width="38" height="6" fill="#ff9b54" transform="rotate(-8 55 221)"/>
|
||||
<rect x="36" y="216" width="38" height="6" fill="#d6457b" transform="rotate(-8 55 221)"/>
|
||||
<rect x="36" y="228" width="38" height="6" fill="#6c63ff" transform="rotate(-8 55 221)"/>
|
||||
|
||||
<polygon points="118,196 132,208 120,222 106,210" fill="#ffd166" stroke="#18486b" stroke-width="1"/>
|
||||
<polygon points="138,206 154,220 140,236 124,222" fill="#ff8c69" stroke="#18486b" stroke-width="1"/>
|
||||
<polygon points="160,196 176,210 162,226 146,212" fill="#61b5ff" stroke="#18486b" stroke-width="1"/>
|
||||
|
||||
<text x="24" y="266" font-family="Helvetica" font-size="8" fill="#ffffff">tc-lib-pdf SVG feature study</text>
|
||||
<text x="24" y="278" font-family="Helvetica" font-size="4.8" fill="#d9ecff">rect circle ellipse line polyline polygon path text</text>
|
||||
<text x="24" y="286" font-family="Helvetica" font-size="4.8" fill="#d9ecff">gradients opacity dasharray transforms stroke caps and joins</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1">
|
||||
<title>SVG Path and Text Regression Showcase</title>
|
||||
<desc>Each shape is drawn twice: a pale fill from a verbose path and a dark
|
||||
outline from the compact equivalent that path optimizers emit. The two
|
||||
forms describe the same geometry, so the dark outline must trace the
|
||||
pale shape exactly. The text blocks check anchoring, white space
|
||||
handling, style inheritance and multi chunk layout.</desc>
|
||||
|
||||
<defs>
|
||||
<marker id="dot" viewBox="0 0 4 4" refX="2" refY="2" markerWidth="4" markerHeight="4" orient="auto">
|
||||
<circle cx="2" cy="2" r="1.6" fill="#d6457b"/>
|
||||
</marker>
|
||||
<marker id="tip" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto">
|
||||
<path d="M0 0L10 5L0 10z" fill="#0a6e46"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<rect x="0" y="0" width="210" height="297" fill="#ffffff"/>
|
||||
<rect x="6" y="6" width="198" height="285" fill="none" stroke="#18486b" stroke-width="0.6"/>
|
||||
|
||||
<text x="12" y="16" font-family="Helvetica" font-size="6" fill="#18486b">SVG path and text regression showcase</text>
|
||||
<text x="12" y="22" font-family="Helvetica" font-size="3.4" fill="#4a6f8a">Pale fill = verbose form. Dark outline = compact form. They must coincide.</text>
|
||||
<line x1="12" y1="25" x2="198" y2="25" stroke="#18486b" stroke-width="0.4"/>
|
||||
|
||||
<!-- Numbers with no leading digit, packed decimals and exponents. -->
|
||||
<text x="12" y="33" font-family="Helvetica" font-size="3.6" fill="#18486b">1. numbers: .4029 and -.2485 and 9e-1</text>
|
||||
<g transform="translate(20 37) scale(11)">
|
||||
<path fill="#a8d5c2"
|
||||
d="M1.8 0.9C1.8 1.3971 1.3971 1.8 0.9 1.8C0.4029 1.8 0 1.3971 0 0.9C0 0.4029 0.4029 0 0.9 0C1.3971 0 1.8 0.4029 1.8 0.9Z M1.35 0.9C1.35 0.6515 1.1485 0.45 0.9 0.45C0.6515 0.45 0.45 0.6515 0.45 0.9C0.45 1.1485 0.6515 1.35 0.9 1.35C1.1485 1.35 1.35 1.1485 1.35 0.9Z"/>
|
||||
<path fill="none" stroke="#0a6e46" stroke-width="0.05"
|
||||
d="M1.8 9e-1C1.8 1.3971 1.3971 1.8 .9 1.8C.4029 1.8 0 1.3971 0 .9C0 .4029.4029 0 .9 0C1.3971 0 1.8 .4029 1.8 .9Z M1.35 .9c0-.2485-.2015-.45-.45-.45c-.2485 0-.45.2015-.45.45c0 .2485.2015.45.45.45c.2485 0 .45-.2015.45-.45z"/>
|
||||
</g>
|
||||
|
||||
<!-- Elliptical arc flags packed with the surrounding values. -->
|
||||
<text x="110" y="33" font-family="Helvetica" font-size="3.6" fill="#18486b">2. arc flags: a8 8 0 018 8</text>
|
||||
<g transform="translate(112 37) scale(0.62)">
|
||||
<path fill="#bcd8ef"
|
||||
d="M8 0H32A8 8 0 0 1 40 8V24A8 8 0 0 1 32 32H8A8 8 0 0 1 0 24V8A8 8 0 0 1 8 0Z"/>
|
||||
<path fill="none" stroke="#18486b" stroke-width="0.8"
|
||||
d="M8 0H32a8 8 0 018 8v16a8 8 0 01-8 8H8a8 8 0 01-8-8V8a8 8 0 018-8z"/>
|
||||
</g>
|
||||
<g transform="translate(152 37) scale(0.62)">
|
||||
<path fill="#bcd8ef" d="M20 20V0A20 20 0 1 1 0 20Z"/>
|
||||
<path fill="none" stroke="#18486b" stroke-width="0.8" d="M20 20V0a20 20 0 11-20 20z"/>
|
||||
</g>
|
||||
|
||||
<!-- Smooth cubic curveto: the control point mirrors the previous curve. -->
|
||||
<text x="12" y="66" font-family="Helvetica" font-size="3.6" fill="#18486b">3. smooth cubic: C then S then S</text>
|
||||
<g transform="translate(16 70) scale(1.55)">
|
||||
<path fill="none" stroke="#f0c9a0" stroke-width="2.2"
|
||||
d="M0 12C4 0 12 0 16 12C20 24 28 24 32 12C36 0 44 0 48 12"/>
|
||||
<path fill="none" stroke="#a4521a" stroke-width="0.5"
|
||||
d="M0 12C4 0 12 0 16 12S28 24 32 12S44 0 48 12"/>
|
||||
</g>
|
||||
|
||||
<!-- Smooth quadratic curveto: the control point mirrors the previous curve. -->
|
||||
<text x="110" y="66" font-family="Helvetica" font-size="3.6" fill="#18486b">4. smooth quadratic: Q then T then T</text>
|
||||
<g transform="translate(114 70) scale(1.55)">
|
||||
<path fill="none" stroke="#f0c9a0" stroke-width="2.2"
|
||||
d="M0 12Q8 0 16 12Q24 24 32 12Q40 0 48 12"/>
|
||||
<path fill="none" stroke="#a4521a" stroke-width="0.5"
|
||||
d="M0 12Q8 0 16 12T32 12T48 12"/>
|
||||
</g>
|
||||
|
||||
<!-- Compound paths: both fill rules must leave the counter open. -->
|
||||
<text x="12" y="110" font-family="Helvetica" font-size="3.6" fill="#18486b">5. compound path, nonzero</text>
|
||||
<g transform="translate(20 114) scale(0.62)">
|
||||
<path fill="#6c63ff" d="M0 0H40V40H0Z M8 8V32H32V8Z"/>
|
||||
</g>
|
||||
<text x="110" y="110" font-family="Helvetica" font-size="3.6" fill="#18486b">6. compound path, evenodd</text>
|
||||
<g transform="translate(118 114) scale(0.62)">
|
||||
<path fill="#6c63ff" fill-rule="evenodd" d="M0 0H40V40H0Z M8 8H32V32H8Z"/>
|
||||
</g>
|
||||
|
||||
<!-- Text anchoring: every run must line up with its guide. -->
|
||||
<text x="12" y="146" font-family="Helvetica" font-size="3.6" fill="#18486b">7. text-anchor: end, middle, start on the guides</text>
|
||||
<line x1="60" y1="149" x2="60" y2="169" stroke="#d6457b" stroke-width="0.4"/>
|
||||
<line x1="105" y1="149" x2="105" y2="169" stroke="#d6457b" stroke-width="0.4"/>
|
||||
<line x1="150" y1="149" x2="150" y2="169" stroke="#d6457b" stroke-width="0.4"/>
|
||||
<text x="60" y="155" font-family="Helvetica" font-size="4" text-anchor="end" fill="#333333">end</text>
|
||||
<text x="105" y="155" font-family="Helvetica" font-size="4" text-anchor="middle" fill="#333333">middle</text>
|
||||
<text x="150" y="155" font-family="Helvetica" font-size="4" text-anchor="start" fill="#333333">start</text>
|
||||
<text x="60" y="161" font-family="Helvetica" font-size="4" text-anchor="end" fill="#333333">00000000</text>
|
||||
<text x="105" y="161" font-family="Helvetica" font-size="4" text-anchor="middle" fill="#333333">00000000</text>
|
||||
<text x="150" y="161" font-family="Helvetica" font-size="4" text-anchor="start" fill="#333333">00000000</text>
|
||||
<text x="60" y="167" font-family="Helvetica" font-size="4" text-anchor="end" fill="#333333">0</text>
|
||||
<text x="105" y="167" font-family="Helvetica" font-size="4" text-anchor="middle" fill="#333333">0</text>
|
||||
<text x="150" y="167" font-family="Helvetica" font-size="4" text-anchor="start" fill="#333333">0</text>
|
||||
|
||||
<!-- White space: the indentation of this file must never reach the page. -->
|
||||
<text x="12" y="178" font-family="Helvetica" font-size="3.6" fill="#18486b">8. white space and collapsing</text>
|
||||
<text x="16" y="185" font-family="Helvetica" font-size="4" fill="#333333">
|
||||
one line, no leading or trailing blanks
|
||||
</text>
|
||||
<text x="16" y="191" font-family="Helvetica" font-size="4" fill="#333333">three spaces collapsed</text>
|
||||
<text x="16" y="197" font-family="Helvetica" font-size="4" fill="#333333" xml:space="preserve"> xml:space preserve keeps them </text>
|
||||
|
||||
<!-- Inheritance: the children take the presentation attributes of the group. -->
|
||||
<text x="110" y="178" font-family="Helvetica" font-size="3.6" fill="#18486b">9. inherited group style</text>
|
||||
<g fill="#6c63ff" font-family="Helvetica" font-size="4.5">
|
||||
<rect x="114" y="183" width="14" height="10"/>
|
||||
<g stroke="#18486b" stroke-width="0.8">
|
||||
<circle cx="139" cy="188" r="5"/>
|
||||
</g>
|
||||
<text x="150" y="190">inherited</text>
|
||||
</g>
|
||||
<text x="114" y="200" font-family="Helvetica" font-size="3.2" fill="#4a6f8a">Fill and font size from the outer group,</text>
|
||||
<text x="114" y="204" font-family="Helvetica" font-size="3.2" fill="#4a6f8a">the outline from the inner one.</text>
|
||||
|
||||
<!-- Text chunks: each tspan starts where the previous chunk ends. -->
|
||||
<text x="12" y="210" font-family="Helvetica" font-size="3.6" fill="#18486b">10. tspan chunks flow and restore the parent font</text>
|
||||
<text x="16" y="217" font-family="Helvetica" font-size="4.5" fill="#333333">Hello <tspan
|
||||
fill="#d6457b">bright</tspan> and <tspan
|
||||
font-size="3" fill="#0a6e46">small</tspan> world</text>
|
||||
|
||||
<!-- A badge in the shape optimizers produce: packed flags, both sweeps, a
|
||||
counter left open by the reversed inner subpath. -->
|
||||
<text x="12" y="228" font-family="Helvetica" font-size="3.6" fill="#18486b">11. optimizer output: flags and a counter</text>
|
||||
<g transform="translate(20 232) scale(0.52)">
|
||||
<path fill="#f4c7d8"
|
||||
d="M8 0H32A8 8 0 0 1 40 8V24A8 8 0 0 1 32 32H8A8 8 0 0 1 0 24V8A8 8 0 0 1 8 0Z M12 8A4 4 0 0 0 8 12V20A4 4 0 0 0 12 24H28A4 4 0 0 0 32 20V12A4 4 0 0 0 28 8Z"/>
|
||||
<path fill="none" stroke="#d6457b" stroke-width="0.9"
|
||||
d="M8 0H32a8 8 0 018 8v16a8 8 0 01-8 8H8a8 8 0 01-8-8V8a8 8 0 018-8zM12 8a4 4 0 00-4 4v8a4 4 0 004 4h16a4 4 0 004-4v-8a4 4 0 00-4-4z"/>
|
||||
</g>
|
||||
<text x="46" y="240" font-family="Helvetica" font-size="3.2" fill="#4a6f8a">Both sweep directions,</text>
|
||||
<text x="46" y="245" font-family="Helvetica" font-size="3.2" fill="#4a6f8a">every flag packed.</text>
|
||||
|
||||
<!-- Markers sit on the vertices and turn with the segments. -->
|
||||
<text x="110" y="228" font-family="Helvetica" font-size="3.6" fill="#18486b">12. markers on the vertices</text>
|
||||
<path fill="none" stroke="#4a6f8a" stroke-width="0.8"
|
||||
marker-start="url(#dot)" marker-mid="url(#dot)" marker-end="url(#tip)"
|
||||
d="M116 240l18-7 18 7 18-7 18 7"/>
|
||||
|
||||
<line x1="12" y1="256" x2="198" y2="256" stroke="#18486b" stroke-width="0.4"/>
|
||||
<text x="12" y="262" font-family="Helvetica" font-size="3.2" fill="#4a6f8a">A dark outline that leaves its pale shape, a missing outline, a run off its</text>
|
||||
<text x="12" y="267" font-family="Helvetica" font-size="3.2" fill="#4a6f8a">guide, a filled counter, a stray marker or a blank box marks a regression.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1,214 @@
|
||||
%!PS-Adobe-3.0 EPSF
|
||||
%%Creator: Adobe Illustrator
|
||||
%%BoundingBox: -7 0 487 327
|
||||
%%HiResBoundingBox: -6.66162 2.44007e-05 486.662 326.648
|
||||
%AI5_FileFormat 3
|
||||
%%EndComments
|
||||
%%BeginProlog
|
||||
%%EndProlog
|
||||
%%BeginSetup
|
||||
%%EndSetup
|
||||
1 XR
|
||||
%AI5_BeginLayer
|
||||
1 1 1 1 0 0 -1 49 80 161 Lb
|
||||
(New Layer) Ln
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
[] 0 d
|
||||
1.402287 w
|
||||
0 j
|
||||
0 J
|
||||
0.263000 0.290000 0.898000 0.263000 k
|
||||
72.7885 255.643 m
|
||||
277.08 286.778 L
|
||||
425.478 260.993 L
|
||||
408.269 190.301 L
|
||||
113.504 181.247 L
|
||||
113.504 181.247 72.9813 241.769 72.7885 255.643 C
|
||||
b
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
1 j
|
||||
0.094000 0.102000 0.369000 0.016000 k
|
||||
423.247 259.914 m
|
||||
240.217 207.097 L
|
||||
240.635 0.701168 L
|
||||
397.776 116.053 L
|
||||
423.247 259.914 L
|
||||
b
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
0.133000 0.141000 0.541000 0.035000 k
|
||||
72.1745 254.207 m
|
||||
240.217 207.097 L
|
||||
240.561 0.783816 L
|
||||
101.054 87.946 L
|
||||
72.1745 254.207 L
|
||||
b
|
||||
0.047000 0.059000 0.184000 0.004000 k
|
||||
423.247 259.914 m
|
||||
308.187 51.1553 L
|
||||
396.862 116.972 L
|
||||
423.247 259.914 L
|
||||
f
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
0 j
|
||||
0.047000 0.059000 0.184000 0.004000 k
|
||||
479.312 250.415 m
|
||||
423.613 260.243 L
|
||||
240.385 206.966 L
|
||||
314.061 186.394 L
|
||||
479.312 250.415 L
|
||||
b
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
0.047000 0.059000 0.184000 0.004000 k
|
||||
69.9121 254.273 m
|
||||
237.965 207.131 L
|
||||
163.618 164.537 L
|
||||
0.687544 234.686 L
|
||||
69.9121 254.273 L
|
||||
b
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
0.047000 0.059000 0.184000 0.004000 k
|
||||
242.971 319.299 m
|
||||
275.613 286.233 L
|
||||
72.5703 254.295 L
|
||||
16.555 296.161 L
|
||||
242.971 319.299 L
|
||||
b
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
0.133000 0.141000 0.541000 0.035000 k
|
||||
423.496 260.684 m
|
||||
275.426 286.441 L
|
||||
307.326 316.69 L
|
||||
462.053 292.606 L
|
||||
423.496 260.684 L
|
||||
b
|
||||
0.196000 0.227000 0.871000 0.106000 k
|
||||
75.26 254.037 m
|
||||
274.806 285.371 L
|
||||
227.928 211.257 L
|
||||
163.396 228.836 130.937 238.701 75.26 254.037 C
|
||||
f
|
||||
0.620000 0.580000 0.435000 0.996000 K
|
||||
1 j
|
||||
0.169000 0.314000 0.424000 0.094000 k
|
||||
275.528 286.329 m
|
||||
274.75 216.78 L
|
||||
275.528 286.329 L
|
||||
b
|
||||
0.031000 0.949000 0.745000 0.729000 k
|
||||
285.929 160.982 m
|
||||
285.929 160.982 285.078 139.734 285.078 139.734 C
|
||||
285.078 139.734 275.378 135.096 275.378 135.096 C
|
||||
275.378 135.096 273.058 57.6061 273.058 57.6061 C
|
||||
273.058 57.6061 257.133 47.3536 257.133 47.3536 C
|
||||
257.133 47.3536 258.059 126.816 258.059 126.816 C
|
||||
258.059 126.816 247.186 121.618 247.186 121.618 C
|
||||
247.186 121.618 247.186 144.26 247.186 144.26 C
|
||||
247.186 144.26 285.929 160.982 285.929 160.982 C
|
||||
F
|
||||
0.031000 0.949000 0.745000 0.729000 k
|
||||
320.884 135.342 m
|
||||
320.884 135.342 307.279 128.129 307.279 128.129 C
|
||||
307.279 128.129 308.36 144.944 308.36 144.944 C
|
||||
308.681 149.948 308.724 153.011 308.483 154.097 C
|
||||
308.268 155.24 307.632 155.567 306.572 155.073 C
|
||||
305.368 154.512 304.553 153.381 304.135 151.687 C
|
||||
303.718 149.995 303.36 146.608 303.063 141.565 C
|
||||
303.063 141.565 300.477 97.6864 300.477 97.6864 C
|
||||
300.22 93.3298 300.208 90.6032 300.439 89.4791 C
|
||||
300.668 88.3599 301.318 88.1316 302.385 88.7881 C
|
||||
303.403 89.4149 304.103 90.4684 304.487 91.9528 C
|
||||
304.894 93.4524 305.253 96.6211 305.567 101.497 C
|
||||
305.567 101.497 306.297 112.86 306.297 112.86 C
|
||||
306.297 112.86 319.718 120.438 319.718 120.438 C
|
||||
319.718 120.438 319.446 116.964 319.446 116.964 C
|
||||
318.734 107.862 317.873 101.293 316.856 97.1389 C
|
||||
315.864 93.0164 314.026 88.8059 311.329 84.474 C
|
||||
308.636 80.1307 305.421 76.743 301.646 74.2975 C
|
||||
297.651 71.7096 294.365 70.7251 291.812 71.3887 C
|
||||
289.213 72.064 287.545 74.2699 286.838 78.0362 C
|
||||
286.121 81.8925 285.954 88.3297 286.349 97.4441 C
|
||||
286.349 97.4441 287.575 125.751 287.575 125.751 C
|
||||
287.89 133.007 288.277 138.586 288.737 142.421 C
|
||||
289.202 146.323 290.251 150.369 291.883 154.544 C
|
||||
293.54 158.732 295.716 162.4 298.394 165.529 C
|
||||
301.078 168.689 304.052 170.959 307.296 172.342 C
|
||||
311.621 174.188 315.02 174.154 317.521 172.296 C
|
||||
319.974 170.473 321.427 167.541 321.911 163.514 C
|
||||
322.39 159.578 322.275 153.119 321.579 144.225 C
|
||||
321.579 144.225 320.884 135.342 320.884 135.342 C
|
||||
F
|
||||
0.031000 0.949000 0.745000 0.729000 k
|
||||
*u
|
||||
329.084 179.607 m
|
||||
329.084 179.607 342.074 185.214 342.074 185.214 C
|
||||
345.446 186.669 347.94 187.235 349.586 186.932 C
|
||||
351.233 186.642 352.374 185.695 353.019 184.1 C
|
||||
353.677 182.527 353.999 180.418 353.991 177.777 C
|
||||
354.005 175.2 353.703 171.072 353.088 165.429 C
|
||||
353.088 165.429 352.244 157.683 352.244 157.683 C
|
||||
351.634 152.084 350.908 147.89 350.063 145.056 C
|
||||
349.22 142.228 347.957 139.718 346.265 137.514 C
|
||||
344.583 135.308 342.474 133.487 339.919 132.046 C
|
||||
339.919 132.046 336.736 130.25 336.736 130.25 C
|
||||
336.736 130.25 333.512 96.527 333.512 96.527 C
|
||||
333.512 96.527 321.545 88.8222 321.545 88.8222 C
|
||||
321.545 88.8222 329.084 179.607 329.084 179.607 C
|
||||
F
|
||||
340.42 168.795 m
|
||||
340.42 168.795 338.184 145.407 338.184 145.407 C
|
||||
338.526 145.552 338.82 145.69 339.068 145.822 C
|
||||
340.172 146.404 340.98 147.319 341.498 148.568 C
|
||||
342.038 149.863 342.473 152.174 342.805 155.518 C
|
||||
342.805 155.518 343.55 163.014 343.55 163.014 C
|
||||
343.863 166.167 343.82 168.111 343.416 168.832 C
|
||||
343.011 169.557 342.015 169.547 340.42 168.795 C
|
||||
F
|
||||
*U
|
||||
0.031000 0.949000 0.745000 0.729000 k
|
||||
*u
|
||||
359.204 192.607 m
|
||||
359.204 192.607 367.556 196.212 367.556 196.212 C
|
||||
372.753 198.454 376.114 199.414 377.734 199.14 C
|
||||
379.351 198.877 380.446 197.777 381.03 195.854 C
|
||||
381.608 193.948 381.815 191.642 381.655 188.934 C
|
||||
381.502 186.28 380.88 180.934 379.804 172.981 C
|
||||
379.804 172.981 375.968 144.653 375.968 144.653 C
|
||||
375.021 137.654 374.236 132.926 373.604 130.399 C
|
||||
372.993 127.921 372.216 125.786 371.268 123.986 C
|
||||
370.323 122.215 369.243 120.698 368.023 119.43 C
|
||||
366.801 118.187 365.012 116.807 362.638 115.279 C
|
||||
362.638 115.279 349.593 106.88 349.593 106.88 C
|
||||
349.593 106.88 359.204 192.607 359.204 192.607 C
|
||||
F
|
||||
368.395 181.985 m
|
||||
368.395 181.985 361.644 126.918 361.644 126.918 C
|
||||
363.113 127.815 364.084 128.947 364.566 130.32 C
|
||||
365.053 131.727 365.629 135.077 366.301 140.416 C
|
||||
366.301 140.416 370.368 172.752 370.368 172.752 C
|
||||
370.86 176.666 371.12 179.163 371.145 180.223 C
|
||||
371.168 181.285 371.006 181.972 370.654 182.282 C
|
||||
370.306 182.629 369.555 182.531 368.395 181.985 C
|
||||
F
|
||||
*U
|
||||
0.031000 0.949000 0.745000 0.729000 k
|
||||
387.58 204.854 m
|
||||
387.58 204.854 403.348 211.659 403.348 211.659 C
|
||||
403.348 211.659 400.803 195.062 400.803 195.062 C
|
||||
400.803 195.062 394.579 192.087 394.579 192.087 C
|
||||
394.579 192.087 392.296 176.619 392.296 176.619 C
|
||||
392.296 176.619 397.801 179.482 397.801 179.482 C
|
||||
397.801 179.482 395.533 164.634 395.533 164.634 C
|
||||
395.533 164.634 390.075 161.574 390.075 161.574 C
|
||||
390.075 161.574 385.406 129.937 385.406 129.937 C
|
||||
385.406 129.937 376.374 124.122 376.374 124.122 C
|
||||
376.374 124.122 387.58 204.854 387.58 204.854 C
|
||||
F
|
||||
LB
|
||||
%AI5_EndLayer--
|
||||
%AI5_BeginLayer
|
||||
1 1 1 1 0 0 -1 49 80 161 Lb
|
||||
(MasterLayer 1) Ln
|
||||
LB
|
||||
%AI5_EndLayer--
|
||||
%%Trailer
|
||||
%%EOF
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="600"
|
||||
height="400"
|
||||
id="tcpdf_box">
|
||||
<path
|
||||
d="M 90.985619,80.446426 346.35007,41.527969 531.84796,73.758171 510.33606,162.12434 141.88004,173.44107 c 0,0 -50.653416,-75.65219 -50.894421,-92.994643 z"
|
||||
id="path3233"
|
||||
style="fill:#a0892c;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="M 529.05896,75.10788 300.27124,141.12856 300.79367,399.12354 497.22012,254.93323 529.05896,75.10788 z"
|
||||
id="path2459"
|
||||
style="fill:#e9ddaf;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-linejoin:round;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="M 90.218147,82.241417 300.27124,141.12855 300.7012,399.02023 126.31743,290.06747 90.218147,82.241417 z"
|
||||
id="path3231"
|
||||
style="fill:#decd87;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-linejoin:round;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="M 529.05896,75.10788 385.23331,336.05582 496.07782,253.785 529.05896,75.10788 z"
|
||||
id="path3204"
|
||||
style="fill:#f4eed7;fill-rule:evenodd" />
|
||||
<path
|
||||
d="M 599.14056,86.981453 529.51617,74.695641 300.48178,141.29306 392.57645,167.00775 599.14056,86.981453 z"
|
||||
id="path3243"
|
||||
style="fill:#f4eed7;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="M 87.390083,82.159248 297.45667,141.08572 204.52271,194.32928 0.85943,106.64266 87.390083,82.159248 z"
|
||||
id="path3245"
|
||||
style="fill:#f4eed7;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="M 303.71381,0.87646 344.51688,42.208691 90.712837,82.130967 20.69376,29.79868 303.71381,0.876461 z"
|
||||
id="path3247"
|
||||
style="fill:#f4eed7;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="M 529.36993,74.145378 344.28207,41.9492 384.15726,4.13702 577.56598,34.24292 529.36993,74.145378 z"
|
||||
id="path3263"
|
||||
style="fill:#decd87;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="M 94.075058,82.454048 343.50751,43.286419 284.91046,135.92899 C 204.24522,113.95545 163.67139,101.62348 94.075058,82.454049 z"
|
||||
id="path3206"
|
||||
style="fill:#c8ab37;fill-rule:evenodd" />
|
||||
<path
|
||||
d="m 344.40955,42.08839 -0.97239,86.93644 0.97239,-86.93644 z"
|
||||
id="path2426"
|
||||
style="fill:#caa98d;fill-rule:evenodd;stroke:#000000;stroke-width:1.752859;stroke-linejoin:round;stroke-miterlimit:4" />
|
||||
<path
|
||||
d="m 357.41141,198.77278 c 0,0 -1.06345,26.55933 -1.06345,26.55933 0,0 -12.12588,5.79739 -12.12588,5.79739 0,0 -2.89969,96.8629 -2.89969,96.8629 0,0 -19.9061,12.81561 -19.9061,12.81561 0,0 1.15698,-99.32809 1.15698,-99.32809 0,0 -13.59121,6.49803 -13.59121,6.49803 0,0 0,-28.30334 0,-28.30334 0,0 48.42935,-20.90183 48.42935,-20.90183"
|
||||
id="path5441"
|
||||
style="fill:#550000" />
|
||||
<path
|
||||
d="m 401.10504,230.8226 c 0,0 -17.00665,9.0165 -17.00665,9.0165 0,0 1.3512,-21.019 1.3512,-21.019 0.402,-6.2545 0.45517,-10.08344 0.15475,-11.44165 -0.26965,-1.42879 -1.06461,-1.83763 -2.3894,-1.22009 -1.50556,0.70219 -2.52317,2.11514 -3.04563,4.2332 -0.52157,2.11482 -0.96939,6.34812 -1.34085,12.65235 0,0 -3.23221,54.84809 -3.23221,54.84809 -0.32101,5.44577 -0.33578,8.85397 -0.048,10.25909 0.28671,1.39908 1.09888,1.68448 2.43259,0.86377 1.27319,-0.78342 2.14758,-2.10034 2.62838,-3.95581 0.50837,-1.87454 0.95707,-5.83545 1.34897,-11.93002 0,0 0.91309,-14.20398 0.91309,-14.20398 0,0 16.77621,-9.47276 16.77621,-9.47276 0,0 -0.33963,4.34254 -0.33963,4.34254 -0.89019,11.37775 -1.9667,19.58865 -3.23806,24.78162 -1.24018,5.15307 -3.53693,10.4162 -6.90912,15.83102 -3.36563,5.4292 -7.3844,9.66376 -12.10367,12.72073 -4.99368,3.23487 -9.10043,4.46546 -12.29227,3.63599 -3.24878,-0.84418 -5.33295,-3.60156 -6.21771,-8.30939 -0.89523,-4.8204 -1.10458,-12.86691 -0.61096,-24.25988 0,0 1.53271,-35.38347 1.53271,-35.38347 0.3931,-9.07071 0.87778,-16.0441 1.45276,-20.83719 0.58109,-4.87754 1.8923,-9.93605 3.93183,-15.15415 2.07186,-5.235 4.79159,-9.82054 8.13882,-13.73193 3.35501,-3.94881 7.07321,-6.78658 11.12744,-8.51622 5.4072,-2.30643 9.65549,-2.2641 12.78149,0.0581 3.06675,2.27881 4.88321,5.94397 5.48707,10.97809 0.5997,4.91933 0.45568,12.99251 -0.41431,24.11017 0,0 -0.86871,11.10411 -0.86871,11.10411"
|
||||
id="path5443"
|
||||
style="fill:#550000" />
|
||||
<path
|
||||
d="m 411.35443,175.49126 c 0,0 16.23862,-7.00843 16.23862,-7.00843 4.21411,-1.81866 7.33169,-2.52597 9.38946,-2.14839 2.05817,0.3633 3.48441,1.54648 4.29062,3.53996 0.82251,1.9665 1.22608,4.60317 1.21613,7.90484 0.0169,3.22044 -0.36075,8.38028 -1.12943,15.43508 0,0 -1.05478,9.68189 -1.05478,9.68189 -0.76248,6.99831 -1.66961,12.24153 -2.72592,15.78421 -1.05399,3.53464 -2.6333,6.67149 -4.74774,9.42722 -2.10278,2.75729 -4.73932,5.03327 -7.93247,6.83464 0,0 -3.97955,2.24502 -3.97955,2.24502 0,0 -4.02936,42.15401 -4.02936,42.15401 0,0 -14.95935,9.63092 -14.95935,9.63092 0,0 9.42377,-113.48097 9.42377,-113.48097 m 14.17023,13.51561 c 0,0 -2.79438,29.23405 -2.79438,29.23405 0.42658,-0.18139 0.79483,-0.35402 1.10511,-0.5179 1.37976,-0.72847 2.39001,-1.87172 3.03671,-3.4328 0.67474,-1.61934 1.21869,-4.50798 1.63415,-8.6878 0,0 0.93119,-9.36968 0.93119,-9.36968 0.39178,-3.9412 0.33706,-6.37085 -0.16742,-7.27288 -0.50681,-0.90578 -1.75189,-0.89307 -3.74564,0.0468"
|
||||
id="path5445"
|
||||
style="fill:#550000" />
|
||||
<path
|
||||
d="m 449.00479,159.24159 c 0,0 10.44077,-4.5061 10.44077,-4.5061 6.49575,-2.80348 10.69668,-4.00293 12.72158,-3.6608 2.0213,0.32964 3.39048,1.7039 4.12034,4.10832 0.72277,2.38149 0.98129,5.26491 0.78176,8.64975 -0.19201,3.31783 -0.96899,9.99964 -2.31472,19.94068 0,0 -4.79395,35.41017 -4.79395,35.41017 -1.18439,8.74899 -2.16592,14.65866 -2.95572,17.8175 -0.76312,3.09777 -1.73532,5.76644 -2.91974,8.01586 -1.18118,2.21374 -2.5317,4.11101 -4.05642,5.69523 -1.52753,1.55346 -3.76374,3.27924 -6.73096,5.18953 0,0 -16.30603,10.49793 -16.30603,10.49793 0,0 12.01309,-107.15807 12.01309,-107.15807 m 11.48944,13.27721 c 0,0 -8.43966,68.83415 -8.43966,68.83415 1.83639,-1.12169 3.05044,-2.53693 3.65325,-4.25322 0.60837,-1.758 1.3288,-5.94594 2.16813,-12.61931 0,0 5.08401,-40.4202 5.08401,-40.4202 0.61536,-4.89276 0.94013,-8.01438 0.9708,-9.3384 0.0297,-1.32778 -0.17337,-2.18634 -0.61277,-2.57413 -0.43551,-0.43419 -1.37487,-0.31191 -2.82376,0.37111"
|
||||
id="path5447"
|
||||
style="fill:#550000" />
|
||||
<path
|
||||
d="m 484.47485,143.93306 c 0,0 19.70978,-8.50664 19.70978,-8.50664 0,0 -3.18149,20.74545 -3.18149,20.74545 0,0 -7.77993,3.71959 -7.77993,3.71959 0,0 -2.85361,19.33512 -2.85361,19.33512 0,0 6.88156,-3.57958 6.88156,-3.57958 0,0 -2.83499,18.56089 -2.83499,18.56089 0,0 -6.82193,3.82412 -6.82193,3.82412 0,0 -5.83667,39.54715 -5.83667,39.54715 0,0 -11.29004,7.26862 -11.29004,7.26862 0,0 14.00732,-100.91472 14.00732,-100.91472"
|
||||
id="path5449"
|
||||
style="fill:#550000" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,328 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
width="12cm"
|
||||
height="6cm"
|
||||
id="svg2">
|
||||
<desc
|
||||
id="desc4">TCPDF SVG EXAMPLE</desc>
|
||||
<defs
|
||||
id="defs42">
|
||||
<radialGradient
|
||||
cx="85"
|
||||
cy="15"
|
||||
r="5.25"
|
||||
fx="85"
|
||||
fy="15"
|
||||
id="radialGradient2865"
|
||||
xlink:href="#MyRGradient"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
cx="60"
|
||||
cy="25"
|
||||
r="10.5"
|
||||
fx="60"
|
||||
fy="25"
|
||||
id="radialGradient2867"
|
||||
xlink:href="#MyRGradient"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
cx="17.82198"
|
||||
cy="28.055244"
|
||||
r="10.871407"
|
||||
fx="17.82198"
|
||||
fy="28.055244"
|
||||
id="radialGradient2869"
|
||||
xlink:href="#MyRGradient"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.6200333,0,0,1.8396889,173.9517,-9.005912)" />
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient5087"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<linearGradient
|
||||
id="linearGradient5075">
|
||||
<stop
|
||||
id="stop5077"
|
||||
style="stop-color:#ffff00;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop5079"
|
||||
style="stop-color:#ff0000;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient2846"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<linearGradient
|
||||
id="linearGradient2848">
|
||||
<stop
|
||||
id="stop2850"
|
||||
style="stop-color:#ffff00;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop2852"
|
||||
style="stop-color:#ff0000;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient2854"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<linearGradient
|
||||
id="linearGradient2856">
|
||||
<stop
|
||||
id="stop2858"
|
||||
style="stop-color:#ffff00;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop2860"
|
||||
style="stop-color:#ff0000;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient2862"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<linearGradient
|
||||
id="linearGradient2864">
|
||||
<stop
|
||||
id="stop2866"
|
||||
style="stop-color:#ffff00;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop2868"
|
||||
style="stop-color:#ff0000;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient2885"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<radialGradient
|
||||
cx="60"
|
||||
cy="25"
|
||||
r="10.5"
|
||||
fx="60"
|
||||
fy="25"
|
||||
id="radialGradient5215"
|
||||
xlink:href="#MyRGradient"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient5223"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient5245"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient5261"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(3.2520801,0,0,1.0907419,-234.6921,-1.613686)" />
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient5264"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.53063427,0,0,0.17133835,-41.5959,-53.579631)" />
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient5267"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.53063427,0,0,0.17133835,-41.5959,-53.579631)" />
|
||||
<radialGradient
|
||||
cx="184.10963"
|
||||
cy="476.55164"
|
||||
r="74.151497"
|
||||
fx="184.10963"
|
||||
fy="476.55164"
|
||||
id="radialGradient5270"
|
||||
xlink:href="#linearGradient5075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.53063427,0,0,0.17133835,-41.5959,-53.579631)" />
|
||||
<radialGradient
|
||||
cx="85"
|
||||
cy="15"
|
||||
r="5.25"
|
||||
fx="85"
|
||||
fy="15"
|
||||
id="radialGradient5295"
|
||||
xlink:href="#MyRGradient"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<linearGradient
|
||||
x1="2.4930596"
|
||||
y1="8.1225491"
|
||||
x2="58.448399"
|
||||
y2="8.1225491"
|
||||
id="MyLGradient"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.1674701,3.2244804e-8,-1.0401032e-8,0.46846403,253.27742,-193.75856)">
|
||||
<stop
|
||||
id="stop7"
|
||||
style="stop-color:#ff6600;stop-opacity:1"
|
||||
offset="0.05" />
|
||||
<stop
|
||||
id="stop9"
|
||||
style="stop-color:#ffff66;stop-opacity:1"
|
||||
offset="0.94999999" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="MyRGradient">
|
||||
<stop
|
||||
id="stop12"
|
||||
style="stop-color:#0033ff;stop-opacity:1"
|
||||
offset="0.05" />
|
||||
<stop
|
||||
id="stop14"
|
||||
style="stop-color:#ffff66;stop-opacity:1"
|
||||
offset="0.94999999" />
|
||||
</radialGradient>
|
||||
<rect
|
||||
width="120.08073"
|
||||
height="25.367481"
|
||||
rx="3.602421"
|
||||
ry="2.5367482"
|
||||
x="259.28146"
|
||||
y="-189.53065"
|
||||
transform="matrix(0.71626866,0.69782463,-0.72008162,0.69388937,0,0)"
|
||||
id="rect16"
|
||||
style="fill:url(#MyLGradient);stroke:#0000ff;stroke-width:1.00766146" />
|
||||
<ellipse
|
||||
cx="90"
|
||||
cy="30"
|
||||
rx="20"
|
||||
ry="10"
|
||||
transform="matrix(1.4285714,0,0,1.4285714,178.03709,88.814199)"
|
||||
id="ellipse20"
|
||||
style="fill:#00ff00;stroke:#008000;stroke-width:1" />
|
||||
<path
|
||||
d="m 199.75816,42.607008 c 0,-25.80645 38.7097,-25.80645 38.7097,0 0,25.80645 38.70969,25.80645 38.70969,0 z"
|
||||
id="path30"
|
||||
style="fill:url(#radialGradient2869);stroke:#0000ff;stroke-width:1.29032314" />
|
||||
<path
|
||||
d="m 56.981711,101.40999 q 38.411107,-48.013879 76.822209,0 38.41109,48.01387 76.8222,0"
|
||||
id="path32"
|
||||
style="fill:none;stroke:#008000;stroke-width:0.96027768" />
|
||||
<path
|
||||
d="m 56.981711,101.40999 38.411107,-48.013879 38.411102,48.013879 38.41109,48.01387 38.41111,-48.01387"
|
||||
id="path34"
|
||||
style="fill:none;stroke:#888888;stroke-width:0.38411102" />
|
||||
<line
|
||||
x1="158.17"
|
||||
y1="196.27382"
|
||||
x2="403.61057"
|
||||
y2="196.27382"
|
||||
id="line22"
|
||||
style="fill:#ff0000;stroke:#ff0000;stroke-width:2.72711658;stroke-opacity:1" />
|
||||
<text
|
||||
x="158.15259"
|
||||
y="182.61755"
|
||||
id="text38"
|
||||
style="font-size:35.67964172px;font-weight:bold;fill:#0000ff;font-family:Helvetica">www.tcpdf.org</text>
|
||||
<polygon
|
||||
points="80,10 90,10 90,20 80,20 80,10 "
|
||||
transform="matrix(4.7619048,0,0,4.7619048,-28.55484,-29.862646)"
|
||||
id="polygon26"
|
||||
style="fill:url(#radialGradient5295);stroke:#ff0000;stroke-width:0.5" />
|
||||
<path
|
||||
d="M 172.22678,86.983374 H 140.4086 A 31.818187,31.818187 0 1 0 172.22678,55.16517 z"
|
||||
id="path10"
|
||||
style="fill:#ff0000;stroke:#0000ff;stroke-width:1.06060624" />
|
||||
<path
|
||||
d="M 166.92376,81.680334 V 49.86215 a 31.818187,31.818187 0 0 0 -31.81821,31.818184 z"
|
||||
id="path12"
|
||||
style="fill:#ffff00;stroke:#0000ff;stroke-width:1.06060624" />
|
||||
<path
|
||||
d="m 191.9699,155.18875 13.78038,-6.89018 a 7.7034622,7.7034622 0 1 1 13.78037,-6.89018 l 13.78033,-6.89018 a 15.386158,7.6930793 60 0 1 13.78034,-6.89016 l 13.78034,-6.89017 a 23.073485,7.6911617 60 0 1 13.78037,-6.89019 l 13.78037,-6.89017 a 30.761945,7.6904861 60 1 1 13.78036,-6.89019 l 13.78034,-6.890167"
|
||||
id="path14"
|
||||
style="fill:none;stroke:#ff0000;stroke-width:1.37803578" />
|
||||
<circle
|
||||
cx="60"
|
||||
cy="25"
|
||||
r="10"
|
||||
transform="matrix(2.3809524,0,0,2.3809524,-86.105483,113.11357)"
|
||||
id="circle18"
|
||||
style="fill:url(#radialGradient5215);stroke:#ff0000;stroke-width:1" />
|
||||
<path
|
||||
d="m 32.361418,52.28906 48.780487,0 -24.39025,48.78049 z"
|
||||
id="path28"
|
||||
style="fill:#ffff00;stroke:#0000ff;stroke-width:1.21951222" />
|
||||
<image
|
||||
xlink:href="tcpdf_logo.jpg"
|
||||
id="image36"
|
||||
height="26.666664"
|
||||
width="80"
|
||||
y="111.32501"
|
||||
x="16.751661" />
|
||||
<text
|
||||
x="13.399332"
|
||||
y="41.580627"
|
||||
id="text5343"
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#008000;font-family:helvetica;font-size:30pt">SVG</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,86 @@
|
||||
# tc-lib-pdf Examples
|
||||
|
||||
This index lists all runnable examples bundled with tc-lib-pdf, from foundational PDF generation to advanced features such as digital signatures, conformance modes (PDF/X and PDF/UA), HTML rendering, graphics, forms, and table-of-contents generation. Use it as a quick map to pick the closest starting point for your use case.
|
||||
|
||||
- [E000_overview.php](E000_overview.php): General feature overview with text, graphics, HTML, SVG, images, barcodes, transparency, gradients, annotations, and bookmarks.
|
||||
- [E001_invoice.php](E001_invoice.php): Invoice layout example with embedded Factur-X / ZUGFeRD metadata.
|
||||
- [E002_font_dump.php](E002_font_dump.php): Font inspection and glyph dump example.
|
||||
- [E003_rtl_languages.php](E003_rtl_languages.php): Right-To-Left (RTL) text rendering example for Persian, Arabic, and Hebrew.
|
||||
- [E004_page_formats.php](E004_page_formats.php): Page format and orientation samples.
|
||||
- [E005_header_footer.php](E005_header_footer.php): Repeating custom page header and footer example with PDF/UA Artifact tagging (`Pagination/Header` and `Pagination/Footer`).
|
||||
- [E006_minimal.php](E006_minimal.php): Minimal "Hello, PDF" setup.
|
||||
- [E007_signature_basic.php](E007_signature_basic.php): PAdES-BASELINE-B digital signature via the fluent `signature()` facade, with visible signature fields.
|
||||
- [E008_signature_timestamp.php](E008_signature_timestamp.php): PAdES-BASELINE-T digital signature with an RFC 3161 TSA timestamp.
|
||||
- [E009_signature_ltv.php](E009_signature_ltv.php): PAdES-BASELINE-LT digital signature with LTV validation material (/DSS and /VRI).
|
||||
- [E010_pdfx.php](E010_pdfx.php): Generic PDF/X mode example for baseline print-oriented output.
|
||||
- [E011_pdfx1a.php](E011_pdfx1a.php): PDF/X-1a conformance example focused on classic CMYK/spot print restrictions.
|
||||
- [E012_pdfx3.php](E012_pdfx3.php): PDF/X-3 conformance example for color-managed print workflows.
|
||||
- [E013_pdfx4.php](E013_pdfx4.php): PDF/X-4 conformance example with modern transparency-capable print output.
|
||||
- [E014_pdfx5.php](E014_pdfx5.php): PDF/X-5 conformance example for advanced PDF/X-4 family workflows.
|
||||
- [E015_pdfua.php](E015_pdfua.php): Generic PDF/UA mode example for accessible tagged PDF output.
|
||||
- [E016_pdfua1.php](E016_pdfua1.php): PDF/UA-1 conformance example.
|
||||
- [E017_pdfua2.php](E017_pdfua2.php): PDF/UA-2 conformance example.
|
||||
- [E018_html_page_span.php](E018_html_page_span.php): HTML page-break behavior example.
|
||||
- [E019_page_regions.php](E019_page_regions.php): Multi-column page regions with content flowing across pages.
|
||||
- [E020_barcodes.php](E020_barcodes.php): Barcode catalog covering supported 1D and 2D barcode types.
|
||||
- [E021_font_stretch_spacing.php](E021_font_stretch_spacing.php): Text spacing controls with font stretching and character spacing.
|
||||
- [E022_cell_borders.php](E022_cell_borders.php): Cell border rendering styles and combinations.
|
||||
- [E023_cell_alignment.php](E023_cell_alignment.php): Cell vertical and horizontal alignment behavior.
|
||||
- [E024_colors.php](E024_colors.php): Color model showcase (grayscale, RGB, CMYK, spot, and Lab) applied to text and graphics.
|
||||
- [E025_transparency.php](E025_transparency.php): Transparency and alpha blending example with overlapping objects.
|
||||
- [E026_text_rendering_modes.php](E026_text_rendering_modes.php): PDF text rendering modes (fill, stroke, clip, and combinations).
|
||||
- [E027_annotations.php](E027_annotations.php): Annotation matrix showing currently supported annotation subtypes.
|
||||
- [E028_text_hyphenation.php](E028_text_hyphenation.php): Hyphenation behavior in justified HTML text.
|
||||
- [E029_xobject_template.php](E029_xobject_template.php): Reusable Form XObject template example with clipping and transparency.
|
||||
- [E030_svg.php](E030_svg.php): SVG rendering showcase using bundled SVG samples.
|
||||
- [E031_html_features.php](E031_html_features.php): HTML and CSS feature showcase for currently implemented parsing and layout support.
|
||||
- [E032_html_lists.php](E032_html_lists.php): Supported HTML list-style and list-item CSS variations.
|
||||
- [E033_geometric_transformations.php](E033_geometric_transformations.php): Geometric transforms including scaling, translation, rotation, skewing, mirroring, and reflection.
|
||||
- [E034_color_gradient_mesh.php](E034_color_gradient_mesh.php): Linear/radial gradients and Coons patch mesh gradients.
|
||||
- [E035_registration_marks.php](E035_registration_marks.php): Crop marks, registration marks, and print color registration bars (including spot colors).
|
||||
- [E036_graphic_methods.php](E036_graphic_methods.php): Drawing primitives showcase (lines, curves, polygons, ellipses, sectors, arrows, and rounded shapes).
|
||||
- [E037_image_methods.php](E037_image_methods.php): Image placement methods for JPEG/PNG variants, color spaces, ICC profiles, and alpha.
|
||||
- [E038_image_clipping.php](E038_image_clipping.php): Image clipping with a custom path mask.
|
||||
- [E039_text_methods.php](E039_text_methods.php): Text APIs for lines, cells, links, spacing, and border positioning.
|
||||
- [E040_annotation_form.php](E040_annotation_form.php): Interactive AcroForm fields (text, radio, checkbox, list/combo, buttons) and JavaScript actions.
|
||||
- [E041_layers_visibility.php](E041_layers_visibility.php): Optional Content Group (layer) visibility for screen-only and print-only content.
|
||||
- [E042_html_form.php](E042_html_form.php): XHTML form-to-PDF mapping example for inputs, selects, textarea, and actions.
|
||||
- [E043_html_tables.php](E043_html_tables.php): HTML table layout showcase including colspan/rowspan, nested tables, CSS styling, and percentage widths.
|
||||
- [E044_toc_index.php](E044_toc_index.php): Bookmark outline example with generated table of contents via addTOC.
|
||||
- [E045_encryption_and_permissions.php](E045_encryption_and_permissions.php): PDF encryption and permission controls with user and owner passwords.
|
||||
- [E046_pangrams.php](E046_pangrams.php): Multilingual pangram showcase covering 17 scripts: Latin, Arabic, Hebrew, Thai, Devanagari, Hangul, Greek, Japanese, Russian, Armenian, Georgian, Tamil, Bengali, Amharic, Khmer, Tibetan, and Chinese.
|
||||
- [E047_remote_resources_security.php](E047_remote_resources_security.php): Remote resource security configuration using fileOptions host/path allowlists, size limits, and cURL controls.
|
||||
- [E048_page_boxes_prepress.php](E048_page_boxes_prepress.php): Prepress page-box guide showing Media/Crop/Bleed/Trim/Art boundaries with visual overlays.
|
||||
- [E049_output_targets_integration.php](E049_output_targets_integration.php): Multi-target output example covering render, download, save-to-file, and MIME attachment workflows.
|
||||
- [E050_shipping_label_barcodes.php](E050_shipping_label_barcodes.php): Production-style shipping label layout using 1D and 2D barcodes with quiet-zone spacing.
|
||||
- [E051_viewer_preferences_navigation.php](E051_viewer_preferences_navigation.php): Viewer preferences, display mode, named destinations, internal link annotations, and bookmarks.
|
||||
- [E052_custom_fonts_fallback.php](E052_custom_fonts_fallback.php): Custom font selection strategy with Unicode fallback across Latin, DejaVu Sans, and Unifont.
|
||||
- [E053_spot_overprint_proof.php](E053_spot_overprint_proof.php): Spot color tint ramps and overprint simulation using tc-lib-color and tc-lib-pdf-graph.
|
||||
- [E054_page_groups_numbering.php](E054_page_groups_numbering.php): Mixed Roman/Arabic page numbering with multi-level bookmarks and auto-generated TOC.
|
||||
- [E055_page_reorder_booklet.php](E055_page_reorder_booklet.php): Page reordering via Page::move() with a booklet imposition summary and saddle-stitch spread grid.
|
||||
- [E056_encryption_cert_recipients.php](E056_encryption_cert_recipients.php): Certificate-based (public-key) PDF encryption with per-recipient permission matrices using tc-lib-pdf-encrypt.
|
||||
- [E057_multisignature_incremental.php](E057_multisignature_incremental.php): Multi-signature approval workflow with a primary certifier signature and reserved empty approval fields.
|
||||
- [E058_embedded_files_portfolio.php](E058_embedded_files_portfolio.php): PDF as a document container embedding CSV, XML, and JSON attachments with annotation links.
|
||||
- [E059_document_javascript.php](E059_document_javascript.php): Document-level JavaScript using appendRawJavaScript and addRawJavaScriptObj for open-action, print, and close event triggers.
|
||||
- [E060_custom_xmp_metadata.php](E060_custom_xmp_metadata.php): Custom XMP namespace injection (IPTC rights, XMP-MM version history, application metadata) via setCustomXMP.
|
||||
- [E061_user_rights_reader_extensions.php](E061_user_rights_reader_extensions.php): Adobe Reader extension rights (UR3 signature) via setUserRights to enable form-filling, commenting, and saving in free Reader.
|
||||
- [E062_bidi_mixed_rtl_ltr.php](E062_bidi_mixed_rtl_ltr.php): Mixed bidirectional typography with mid-document setRTL switching and inline Hebrew/Latin runs on the same page.
|
||||
- [E063_manual_tag_tree.php](E063_manual_tag_tree.php): Manual PDF/UA structure-element tagging with beginStructElem/endStructElem plus Artifact-tagged decorative layout separators.
|
||||
- [E064_custom_hyphenation_dictionary.php](E064_custom_hyphenation_dictionary.php): External TeX hyphenation pattern loading via loadTexHyphenPatterns and setTexHyphenPatterns with a side-by-side Dutch column comparison.
|
||||
- [E065_import_single_page.php](E065_import_single_page.php): Import one source page as a Form XObject and place it scaled on a destination page.
|
||||
- [E066_import_document_append.php](E066_import_document_append.php): Append all pages from an imported source document and preserve destination flow.
|
||||
- [E067_import_page_region_nup.php](E067_import_page_region_nup.php): Advanced 2x2 N-up composition from imported pages with clipping and centered placement per region.
|
||||
- [E068_font_subset.php](E068_font_subset.php): Font subsetting example showing reduced embedding to only used glyphs.
|
||||
- [E069_html_line_height.php](E069_html_line_height.php): HTML line-height behavior showcase across percentages, absolute units, relative units, and unitless values.
|
||||
- [E070_default_page_content_import.php](E070_default_page_content_import.php): Use defaultPageContent() to place an imported source page as common content on every new page.
|
||||
- [E071_gettextcell_bbox_metrics.php](E071_gettextcell_bbox_metrics.php): Multiline getTextCell block with visible border and printed bbox/textbbox/cellbbox metrics for visual verification.
|
||||
- [E072_import_new_font.php](E072_import_new_font.php): Import a custom TTF/OTF font with tc-lib-pdf-font conversion tooling and use it in tc-lib-pdf.
|
||||
- [E073_css_supported_categories.php](E073_css_supported_categories.php): Consolidated CSS category showcase covering cascade, selectors, box model, typography, float/clear/position, tables, and paged media.
|
||||
- [E074_text_cell_fit_modes.php](E074_text_cell_fit_modes.php): Visual inspection grid for getTextCell() fit modes (T, S, F) including disabled precondition cases.
|
||||
- [E075_external_signature_injection.php](E075_external_signature_injection.php): External/remote signing walkthrough using signature placeholder setup, ByteRange digest export, and injected CMS/PKCS#7 signature bytes.
|
||||
- [E076_absolute_position.php](E076_absolute_position.php): Absolute coordinate positioning within a given page.
|
||||
- [E077_html_table_header_px_unit.php](E077_html_table_header_px_unit.php): HTML table pagination with px document units, verifying replayed header rows keep the same column geometry on continuation pages.
|
||||
- [E078_htmlcell_page_margins.php](E078_htmlcell_page_margins.php): Single page with 100mm top and bottom margins, placing getHTMLCell text blocks in the top border, central content area, and bottom border.
|
||||
- [E079_font_stretch_spacing_matrix.php](E079_font_stretch_spacing_matrix.php): Font stretching (Tz) and character spacing (Tc) matrix across L/C/R/J alignment for both the direct text API and the HTML/CSS font-stretch/letter-spacing engine.
|
||||
- [E080_no_write_regions.php](E080_no_write_regions.php): No-write page regions: text flows around rectangular, trapezoidal, and circular obstacles via `setNoWriteRegions()`, which approximates each obstacle with a stack of rectangular write regions. Each scenario is rendered twice — with `addTextCell()` and with `addHTMLCell()` — producing the same shape-hugging flow and overflowing onto a fresh full-width page.
|
||||
- [E081_signature_pades_lta.php](E081_signature_pades_lta.php): PAdES-BASELINE-LTA archive-timestamped signature: a B-LT signature upgraded via `signature()->upgradeToLta()`, adding a `/Type /DocTimeStamp` archive timestamp over the whole document in a further incremental revision.
|
||||