Skip to content

Commit 9d435fa

Browse files
committed
Updated "Stamper > Various > Tagged" demo
1 parent b1f63eb commit 9d435fa

4 files changed

Lines changed: 119 additions & 62 deletions

File tree

127 KB
Binary file not shown.

classes/Stamper/Stamp/Tagged.php

Lines changed: 84 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,21 @@
22

33
namespace setasign\SetaPDF2\Demos\Stamper\Stamp;
44

5+
use setasign\SetaPDF2\Core\DataStructure\Tree\NameTree;
56
use setasign\SetaPDF2\Core\DataStructure\Tree\NumberTree;
67
use setasign\SetaPDF2\Core\Document;
78
use setasign\SetaPDF2\Core\Document\Action\Action;
89
use setasign\SetaPDF2\Core\Document\OptionalContent\Group;
910
use setasign\SetaPDF2\Core\Document\Page;
1011
use setasign\SetaPDF2\Core\Encoding\Encoding;
12+
use setasign\SetaPDF2\Core\Type\Dictionary\DictionaryHelper;
1113
use setasign\SetaPDF2\Core\Type\PdfArray;
1214
use setasign\SetaPDF2\Core\Type\PdfDictionary;
15+
use setasign\SetaPDF2\Core\Type\PdfIndirectReference;
1316
use setasign\SetaPDF2\Core\Type\PdfName;
1417
use setasign\SetaPDF2\Core\Type\PdfNumeric;
1518
use setasign\SetaPDF2\Core\Type\PdfString;
19+
use setasign\SetaPDF2\NotImplementedException;
1620
use setasign\SetaPDF2\Stamper\Stamp\AbstractStamp;
1721

1822
/**
@@ -25,26 +29,31 @@ class Tagged extends AbstractStamp
2529
*/
2630
protected $_mainStamp;
2731

32+
protected $_parentId;
2833
protected $_tagName = 'Span';
2934
protected $_title = '';
3035
protected $_actualText = '';
3136
protected $_alternateText = '';
3237
protected $_language = '';
38+
protected $_stampedOnPage;
3339

3440
/**
3541
* The constructor
3642
*
3743
* @param AbstractStamp $mainStamp The main stamp instance
44+
* @param string|null $parentId The ID of the parent structure element. If set to null the new tag
45+
* will be added to the root of the structure tree.
3846
*/
39-
public function __construct(AbstractStamp $mainStamp)
47+
public function __construct(AbstractStamp $mainStamp, ?string $parentId = null)
4048
{
4149
$this->_mainStamp = $mainStamp;
50+
$this->_parentId = $parentId;
4251
}
4352

4453
/**
45-
* @param string $tagName
54+
* @param ?string $tagName
4655
*/
47-
public function setTagName(string $tagName)
56+
public function setTagName(?string $tagName)
4857
{
4958
$this->_tagName = $tagName;
5059
}
@@ -109,34 +118,78 @@ protected function _stamp(Document $document, Page $page, array $stampData)
109118
$structTreeRoot = $document->getCatalog()->getStructTreeRoot();
110119
$structTreeRoot->getDictionary(true);
111120

112-
$pageDict = $page->getObject()->ensure();
121+
$pageDict = PdfDictionary::ensureType($page->getObject());
113122
if (!$pageDict->offsetExists('StructParents')) {
114123
$pageDict->offsetSet(
115124
'StructParents',
116125
new PdfNumeric($structTreeRoot->getAndIncrementParentTreeNextKey())
117126
);
118127
}
119128

120-
$structParentsKey = $pageDict->getValue('StructParents')->getValue();
129+
$structParentsKey = PdfNumeric::ensureType($pageDict->getValue('StructParents'))->getValue();
121130

122131
/** @var NumberTree $parentTree */
123132
$parentTree = $structTreeRoot->getParentTree(true);
124-
$elements = $parentTree->get($structParentsKey);
125-
if ($elements !== false) {
126-
$elements = $elements->ensure();
133+
$parentElements = $parentTree->get($structParentsKey);
134+
if ($parentElements !== false) {
135+
$parentElements = $parentElements->ensure();
127136
} else {
128-
$elements = new PdfArray();
129-
$parentTree->add($structParentsKey, $document->createNewObject($elements));
137+
$parentElements = new PdfArray();
138+
$parentTree->add($structParentsKey, $document->createNewObject($parentElements));
130139
}
131140

132-
$mcid = count($elements);
141+
$mcid = \count($parentElements);
142+
143+
if ($this->_parentId !== null) {
144+
$idTree = $structTreeRoot->getIdTree();
145+
if (!$idTree instanceof NameTree) {
146+
throw new \InvalidArgumentException(\sprintf(
147+
'The parentId (%s) cannot be found.',
148+
$this->_parentId
149+
));
150+
}
151+
152+
$parent = $idTree->get($this->_parentId);
153+
if (!$parent instanceof PdfIndirectReference) {
154+
throw new \InvalidArgumentException(\sprintf(
155+
'The parentId (%s) cannot be found.',
156+
$this->_parentId
157+
));
158+
}
159+
} else {
160+
$parent = $structTreeRoot->getObject();
161+
}
133162

134-
$element = new PdfDictionary([
135-
'K' => new PdfNumeric($mcid),
136-
'P' => $structTreeRoot->getObject(),
137-
'Pg' => $page->getObject(),
138-
'S' => new PdfName($this->_tagName, true)
139-
]);
163+
if ($this->_tagName === null) {
164+
if ($this->_parentId === null) {
165+
throw new \InvalidArgumentException(
166+
'The tagName can only be left, if a parentId is provided.'
167+
);
168+
}
169+
170+
$element = PdfDictionary::ensureType($parent);
171+
$parentElements[] = $parent;
172+
$newKidValue = new PdfNumeric($mcid);
173+
} else {
174+
$element = new PdfDictionary([
175+
'K' => new PdfNumeric($mcid),
176+
'P' => $parent,
177+
'S' => new PdfName($this->_tagName, true)
178+
]);
179+
180+
$newKidValue = $document->createNewObject($element);
181+
$parentElements[] = $newKidValue;
182+
}
183+
184+
if ($this->_tagName === null) {
185+
$pageObjectId = $page->getObject()->getObjectId();
186+
if ($this->_stampedOnPage !== null && $this->_stampedOnPage !== $pageObjectId) {
187+
throw new \InvalidArgumentException('A stamp without a tag-name can only be stamped on a single page.');
188+
}
189+
190+
$element['Pg'] = $page->getObject();
191+
$this->_stampedOnPage = $pageObjectId;
192+
}
140193

141194
if ($this->_title !== '') {
142195
$element->offsetSet('T', new PdfString(
@@ -162,18 +215,26 @@ protected function _stamp(Document $document, Page $page, array $stampData)
162215
));
163216
}
164217

165-
$elementReference = $document->createNewObject($element);
218+
$parentDict = PdfDictionary::ensureType($parent);
219+
$k = DictionaryHelper::getValue($parentDict, 'K');
220+
if ($k === null) {
221+
$k = new PdfArray();
222+
$parentDict->offsetSet('K', $document->createNewObject($k));
223+
}
166224

167-
$elements[] = $elementReference;
225+
if (!$k instanceof PdfArray) {
226+
$k = new PdfArray([$k]);
227+
$parentDict->offsetSet('K', $document->createNewObject($k));
228+
}
168229

169-
$structTreeRoot->addChild($elementReference);
230+
$k[] = $newKidValue;
170231

171232
$canvas = $page->getCanvas();
172233

173234
$properties = new PdfDictionary([
174235
'MCID' => new PdfNumeric($mcid)
175236
]);
176-
$canvas->markedContent()->begin($this->_tagName, $properties);
237+
$canvas->markedContent()->begin($this->_tagName ?? 'Span', $properties);
177238

178239
$this->_mainStamp->_stamp($document, $page, $stampData);
179240

@@ -245,7 +306,7 @@ public function getVisibility()
245306
*/
246307
public function setAction(Action $action)
247308
{
248-
$this->_mainStamp->setAction($action);
309+
throw new NotImplementedException('Actions are actually not implemented for tagged stamps.');
249310
}
250311

251312
/**
@@ -261,7 +322,7 @@ public function getAction()
261322
*/
262323
public function setLink($uri)
263324
{
264-
$this->_mainStamp->setLink($uri);
325+
throw new NotImplementedException('Links are actually not implemented for tagged stamps.');
265326
}
266327

267328
/**
Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
<p>
2-
This demo uses a proxy stamp class which will enclose the stamps in marked-content sequences.
3-
You can define the tag name, title, actual text, alternate text and the language.
2+
This demo uses a proxy stamp class which will enclose the stamps in marked-content sequences and
3+
add it to the documents structure tree.
44
</p>
55
<p>
6-
The tags are appended to the root node of the global tag structure.
7-
</p>
6+
By default the new structure element is appended to the root node of the global tag structure.
7+
To add a stamp as a child of an existing structure element, make sure that it has an ID and
8+
pass this as the <code>$parentId</code> parameter of the constructor.
9+
</p>
10+
<p>
11+
If no individual tag should be created but the one that is resolved by the <code>$parentId</code>, you
12+
have to set the tag-name to <i>null</i>: <code>$stamp->setTagName(null);</code><br />
13+
<b>NOTE: Such stamp can only appear on a single page!</b>
14+
</p>
15+
<p>
16+
You can also define an individual tag name, title, actual text, alternate text and the language.
17+
</p>
18+
<p>
19+
To demonstrate the usage of this class, we added an empty <code>Span</code>-tag to the document element
20+
structure of the PDF and set its ID to <code>date</code>. The demo than adds a text stamp directly into
21+
this prepared structure element.
22+
</p>

public/demos/6-Stamper/3-various/5-tagged-stamp/script.php

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<?php
22

3+
use setasign\SetaPDF2\Core\DataStructure\Color\Rgb;
34
use setasign\SetaPDF2\Demos\Stamper\Stamp\Tagged as TaggedStamp;
45
use setasign\SetaPDF2\Core\Font\TrueType\Subset;
5-
use setasign\SetaPDF2\Core\Image\Image;
66
use setasign\SetaPDF2\Core\Writer\HttpWriter;
7-
use setasign\SetaPDF2\Stamper\Stamp\ImageStamp;
87
use setasign\SetaPDF2\Stamper\Stamp\TextStamp;
98
use setasign\SetaPDF2\Stamper\Stamper;
109

@@ -17,7 +16,7 @@
1716
//$writer = new \setasign\SetaPDF2\Core\Writer\FileWriter('tagged.pdf');
1817
// let's get the document
1918
$document = \setasign\SetaPDF2\Core\Document::loadByFilename(
20-
$assetsDirectory . '/pdfs/Brand-Guide.pdf',
19+
$assetsDirectory . '/pdfs/camtown/Terms-and-Conditions - Tagged.pdf',
2120
$writer
2221
);
2322

@@ -35,44 +34,26 @@
3534
// create a stamp instance
3635
$textStamp = new TextStamp($font, 10);
3736
// set a text
38-
$textStamp->setText('Personalized for John Dow (jon.dow@example.com)');
39-
40-
// create a Tagged stamp instance and pass the text stamp to it
41-
$stamp = new TaggedStamp($textStamp);
37+
$textStamp->setText(date('Y-m-d H:i:s'));
38+
// and its color
39+
$textStamp->setTextColor(new Rgb(240/255, 90/255, 40/255));
40+
41+
// create a Tagged stamp instance and pass the text stamp to it,
42+
// we also define the parent tag found by the id "date".
43+
$stamp = new TaggedStamp($textStamp, 'date');
44+
// we want to add the text content into the existing tag, so let's reset the tag-name
45+
$stamp->setTagName(null);
4246
$stamp->setActualText($textStamp->getText());
43-
$stamp->setTitle('Personalization information of user');
44-
45-
// add the stamp to the stamper instance
46-
$stamper->addStamp($stamp, [
47-
'position' => Stamper::POSITION_CENTER_TOP,
48-
'translateX' => 2,
49-
'translateY' => -2
50-
]);
51-
52-
53-
//--- Create an image stamp and wrap it in a Tagged stamp instance ---//
54-
55-
// get an image instance
56-
$image = Image::getByPath($assetsDirectory . '/pdfs/tektown/Logo.png');
57-
// initiate the image stamp
58-
$imageStamp = new ImageStamp($image);
59-
// set height (and width until no setWidth is set the ratio will retain)
60-
$imageStamp->setHeight(23);
61-
62-
// create a Tagged stamp instance and pass the image stamp to it
63-
$stamp = new TaggedStamp($imageStamp);
64-
$stamp->setTagName('Figure');
65-
$stamp->setAlternateText('Logo of "tektown"');
66-
$stamp->setTitle('tektown');
47+
$stamp->setTitle('Creation of this Terms and Conditions');
6748

6849
// add the stamp to the stamper instance
6950
$stamper->addStamp($stamp, [
70-
'showOnPage' => '2-21',
71-
'position' => Stamper::POSITION_CENTER_BOTTOM,
72-
'translateY' => 10
51+
'showOnPage' => 1,
52+
'position' => Stamper::POSITION_RIGHT_TOP,
53+
'translateX' => -40,
54+
'translateY' => -140,
7355
]);
7456

75-
7657
// execute the stamp process
7758
$stamper->stamp();
7859

0 commit comments

Comments
 (0)