Skip to content

Commit

Permalink
Fix text units
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolaasuni committed Oct 3, 2023
1 parent 1dd08e0 commit 00cec2c
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 79 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"tecnickcom/tc-lib-pdf-encrypt": "^1.6",
"tecnickcom/tc-lib-unicode-data": "^1.7",
"tecnickcom/tc-lib-unicode": "^1.4",
"tecnickcom/tc-lib-pdf-page": "^3.1",
"tecnickcom/tc-lib-pdf-page": "^3.2",
"tecnickcom/tc-lib-pdf-graph": "^1.7"
},
"require-dev": {
Expand Down
20 changes: 19 additions & 1 deletion examples/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -923,10 +923,28 @@
// $pdf->page->addContent($pdf->font->getOutCurrentFont());

// Add text
$txt = $pdf->getTextLine('Test PDF text with justification (stretching).', 0, ($page11['pheight'] - $bfont2['ascent']), $page11['pwidth']);
$txt = $pdf->getTextLine(
'Test PDF text with justification (stretching).',
0,
$pdf->pointsToUserUnit($bfont2['ascent']),
$page11['width']
);

$pdf->page->addContent($txt);

// // get the coordinates of the box containing the last added text string.
// $bbox = $pdf->getLastTextBBox();
// // set link
// $aoid = $pdf->setAnnotation(
// $bbox['llx'],
// $bbox['lly'],
// $bbox['urx'] - $bbox['llx'],
// $bbox['lly'] - $bbox['ury'],
// 'https://tcpdf.org',
// array('subtype'=>'Link')
// );
// $pdf->page->addAnnotRef($aoid);

// ----------

// get PDF document as raw string
Expand Down
2 changes: 1 addition & 1 deletion resources/debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ Vcs-Git: https://github.com/~#VENDOR#~/~#PROJECT#~.git
Package: ~#PKGNAME#~
Provides: php-~#PROJECT#~
Architecture: all
Depends: php (>= 5.4.0), php-date, php-tecnickcom-tc-lib-barcode (<< 2.0.0), php-tecnickcom-tc-lib-barcode (>= 1.17.29), php-tecnickcom-tc-lib-color (<< 2.0.0), php-tecnickcom-tc-lib-color (>= 1.14.28), php-tecnickcom-tc-lib-pdf-image (<< 2.0.0), php-tecnickcom-tc-lib-pdf-image (>= 1.4.9), php-tecnickcom-tc-lib-pdf-font (<< 2.0.0), php-tecnickcom-tc-lib-pdf-font (>= 1.15.0), php-tecnickcom-tc-lib-file (<< 2.0.0), php-tecnickcom-tc-lib-file (>= 1.7.28), php-tecnickcom-tc-lib-pdf-encrypt (<< 2.0.0), php-tecnickcom-tc-lib-pdf-encrypt (>= 1.6.24), php-tecnickcom-tc-lib-unicode-data (<< 2.0.0), php-tecnickcom-tc-lib-unicode-data (>= 1.7.22), php-tecnickcom-tc-lib-unicode (<< 2.0.0), php-tecnickcom-tc-lib-unicode (>= 1.4.22), php-tecnickcom-tc-lib-pdf-page (<< 3.0.0), php-tecnickcom-tc-lib-pdf-page (>= 3.1.10), php-tecnickcom-tc-lib-pdf-graph (<< 2.0.0), php-tecnickcom-tc-lib-pdf-graph (>= 1.7.12), ${misc:Depends}
Depends: php (>= 5.4.0), php-date, php-tecnickcom-tc-lib-barcode (<< 2.0.0), php-tecnickcom-tc-lib-barcode (>= 1.17.29), php-tecnickcom-tc-lib-color (<< 2.0.0), php-tecnickcom-tc-lib-color (>= 1.14.28), php-tecnickcom-tc-lib-pdf-image (<< 2.0.0), php-tecnickcom-tc-lib-pdf-image (>= 1.4.9), php-tecnickcom-tc-lib-pdf-font (<< 2.0.0), php-tecnickcom-tc-lib-pdf-font (>= 1.15.0), php-tecnickcom-tc-lib-file (<< 2.0.0), php-tecnickcom-tc-lib-file (>= 1.7.28), php-tecnickcom-tc-lib-pdf-encrypt (<< 2.0.0), php-tecnickcom-tc-lib-pdf-encrypt (>= 1.6.24), php-tecnickcom-tc-lib-unicode-data (<< 2.0.0), php-tecnickcom-tc-lib-unicode-data (>= 1.7.22), php-tecnickcom-tc-lib-unicode (<< 2.0.0), php-tecnickcom-tc-lib-unicode (>= 1.4.22), php-tecnickcom-tc-lib-pdf-page (<< 3.0.0), php-tecnickcom-tc-lib-pdf-page (>= 3.2.0), php-tecnickcom-tc-lib-pdf-graph (<< 2.0.0), php-tecnickcom-tc-lib-pdf-graph (>= 1.7.12), ${misc:Depends}
Description: PHP Barcode library
This library includes PHP classes to generate PDF documents.
2 changes: 1 addition & 1 deletion resources/rpm/rpm.spec
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Requires: php-composer(%{c_vendor}/tc-lib-unicode-data) >= 1.7.22
Requires: php-composer(%{c_vendor}/tc-lib-unicode) < 2.0.0
Requires: php-composer(%{c_vendor}/tc-lib-unicode) >= 1.4.22
Requires: php-composer(%{c_vendor}/tc-lib-pdf-page) < 3.0.0
Requires: php-composer(%{c_vendor}/tc-lib-pdf-page) >= 3.1.10
Requires: php-composer(%{c_vendor}/tc-lib-pdf-page) >= 3.2.0
Requires: php-composer(%{c_vendor}/tc-lib-pdf-graph) < 2.0.0
Requires: php-composer(%{c_vendor}/tc-lib-pdf-graph) >= 1.7.12

Expand Down
104 changes: 53 additions & 51 deletions src/Output.php
Original file line number Diff line number Diff line change
Expand Up @@ -588,10 +588,10 @@ protected function getOutXObjects()
}
$out .= sprintf(
' /BBox [%F %F %F %F]',
($data['x'] * $this->kunit),
(-$data['y'] * $this->kunit),
(($data['w'] + $data['x']) * $this->kunit),
(($data['h'] - $data['y']) * $this->kunit)
$this->userToPointsUnit($data['x']),
$this->userToPointsUnit(-$data['y']),
$this->userToPointsUnit(($data['w'] + $data['x'])),
$this->userToPointsUnit(($data['h'] - $data['y']))
);
$out .= ' /Matrix [1 0 0 1 0 0]'
.' /Resources <<'
Expand Down Expand Up @@ -691,8 +691,8 @@ protected function getOutDestinations()
foreach ($this->dests as $name => $dst) {
$page = $this->page->getPage($dst['p']);
$poid = $page['n'];
$pgx = ($dst['x'] * $this->page->getKUnit());
$pgy = ($page['pheight'] - ($dst['y'] * $this->page->getKUnit()));
$pgx = $this->userToPointsUnit($dst['x']);
$pgy = ($page['pheight'] - $this->userToPointsUnit($dst['y']));
$out .= ' /'.$name.' '.sprintf('[%u 0 R /XYZ %F %F null]', $poid, $pgx, $pgy);
}
$out .= ' >>'."\n"
Expand Down Expand Up @@ -815,13 +815,13 @@ protected function getOutAnnotations()
$pages = $this->page->getPages();
foreach ($pages as $num => $page) {
foreach ($page['annotrefs'] as $key => $oid) {
$annot = $this->pageAnnots[$oid];
$annot = $this->annotation[$oid];
$annot['opt'] = array_change_key_case($annot['opt'], CASE_LOWER);
$out .= $this->getAnnotationRadiobuttonGroups($annot);
$orx = $annot['x'] * $this->kunit;
$ory = $page['height'] - (($annot['y'] + $annot['h']) * $this->kunit);
$width = $annot['w'] * $this->kunit;
$height = $annot['h'] * $this->kunit;
$orx = $this->userToPointsUnit($annot['x']);
$ory = $page['height'] - $this->userToPointsUnit(($annot['y'] + $annot['h']));
$width = $this->userToPointsUnit($annot['w']);
$height = $this->userToPointsUnit($annot['h']);
$rect = sprintf('%F %F %F %F', $orx, $ory, $orx+$width, $ory+$height);
$out .= $oid.' 0 R'."\n"
.'<<'
Expand All @@ -837,7 +837,7 @@ protected function getOutAnnotations()
$out .= ' /Contents '.$this->getOutTextString($annot['txt'], $oid, true);
}
$out .= ' /P '.$page['n'].' 0 R'
.' /NM '.$this->encrypt->escapeDataString(sprintf('%04u-%04u', $n, $key), $oid)
.' /NM '.$this->encrypt->escapeDataString(sprintf('%04u-%04u', $page['num'], $key), $oid)
.' /M '.$this->getOutDateTimeString($this->docmodtime, $oid)
.$this->getOutAnnotationFlags($annot)
.$this->getAnnotationAppearanceStream($annot, $width, $height)
Expand All @@ -848,14 +848,15 @@ protected function getOutAnnotations()
//$out .= ' /StructParent ';
//$out .= ' /OC ';
$out .= $this->getOutAnnotationMarkups($annot, $oid)
.$this->getOutAnnotationOptSubtype($annot, $pagenum, $oid, $key)
.$this->getOutAnnotationOptSubtype($annot, $num, $oid, $key)
.' >>'."\n"
.'endobj'."\n";
if ($formfield && !isset($this->radiobuttonGroups[$n][$annot['txt']])) {
if ($formfield && !isset($this->radiobuttonGroups[$annot['txt']])) {
$this->objid['form'][] = $oid;
}
}
}
//var_dump($out); exit; //DEBUG
return $out;
}

Expand All @@ -869,17 +870,17 @@ protected function getOutAnnotations()
protected function getAnnotationRadiobuttonGroups($annot)
{
$out = '';
if (empty($this->radiobuttonGroups[$n][$annot['txt']])
|| !is_array($this->radiobuttonGroups[$n][$annot['txt']])) {
if (empty($this->radiobuttonGroups[$annot['txt']])
|| !is_array($this->radiobuttonGroups[$annot['txt']])) {
return $out;
}
$oid = $this->radiobuttonGroups[$n][$annot['txt']]['n'];
$oid = $this->radiobuttonGroups[$annot['txt']]['n'];
$out = $oid.' 0 obj'."\n"
.'<<'
.' /Type /Annot'
.' /Subtype /Widget'
.' /Rect [0 0 0 0]';
if ($this->radiobuttonGroups[$n][$annot['txt']]['#readonly#']) {
if ($this->radiobuttonGroups[$annot['txt']]['#readonly#']) {
// read only
$out .= ' /F 68 /Ff 49153';
} else {
Expand All @@ -891,7 +892,7 @@ protected function getAnnotationRadiobuttonGroups($annot)
}
$out .= ' /FT /Btn /Kids [';
$defval = '';
foreach ($this->radiobuttonGroups[$n][$annot['txt']] as $key => $data) {
foreach ($this->radiobuttonGroups[$annot['txt']] as $key => $data) {
if (isset($data['kid'])) {
$out .= ' '.$data['kid'].' 0 R';
if ($data['def'] !== 'Off') {
Expand All @@ -907,7 +908,7 @@ protected function getAnnotationRadiobuttonGroups($annot)
.'endobj'."\n";
$this->objid['form'][] = $oid;
// store object id to be used on Parent entry of Kids
$this->radiobuttonGroups[$n][$annot['txt']] = $oid;
$this->radiobuttonGroups[$annot['txt']] = $oid;
return $out;
}

Expand Down Expand Up @@ -1329,7 +1330,7 @@ protected function getOutAnnotationOptSubtypeLink($annot, $pagenum, $oid)
// internal link ID
$l = $this->links[$annot['txt']];
$page = $this->page->getPage($l['p']);
$y = ($page['height'] - ($l['y'] * $this->kunit));
$y = ($page['height'] - $this->userToPointsUnit($l['y']));
$out .= sprintf(' /Dest [%u 0 R /XYZ 0 %F null]', $page['n'], $y);
}
$hmodes = array('N', 'I', 'O', 'P');
Expand Down Expand Up @@ -1368,7 +1369,7 @@ protected function getOutAnnotationOptSubtypeFreetext($annot)
if (isset($annot['opt']['cl']) && is_array($annot['opt']['cl'])) {
$out .= ' /CL [';
foreach ($annot['opt']['cl'] as $cl) {
$out .= sprintf('%F ', $cl * $this->kunit);
$out .= sprintf('%F ', $this->userToPointsUnit($cl));
}
$out .= ']';
}
Expand All @@ -1377,10 +1378,10 @@ protected function getOutAnnotationOptSubtypeFreetext($annot)
$out .= ' /IT /'.$annot['opt']['it'];
}
if (isset($annot['opt']['rd']) && is_array($annot['opt']['rd'])) {
$l = $annot['opt']['rd'][0] * $this->kunit;
$r = $annot['opt']['rd'][1] * $this->kunit;
$t = $annot['opt']['rd'][2] * $this->kunit;
$b = $annot['opt']['rd'][3] * $this->kunit;
$l = $this->userToPointsUnit($annot['opt']['rd'][0]);
$r = $this->userToPointsUnit($annot['opt']['rd'][1]);
$t = $this->userToPointsUnit($annot['opt']['rd'][2]);
$b = $this->userToPointsUnit($annot['opt']['rd'][3]);
$out .= ' /RD ['.sprintf('%F %F %F %F', $l, $r, $t, $b).']';
}
$lineendings = array(
Expand Down Expand Up @@ -1580,23 +1581,23 @@ protected function getOutAnnotationOptSubtypePopup($annot)
*/
protected function getOutAnnotationOptSubtypeFileattachment($annot, $key)
{
$out = '';
if (($this->pdfa == 1 ) || ($this->pdfa == 2) || !isset($annot['opt']['fs'])) {
// embedded files are not allowed in PDF/A mode version 1 and 2
return $out;
return '';
}
$filename = basename($annot['opt']['fs']);
if (isset($this->embeddedfiles[$filename]['f'])) {
$out .= ' /FS '.$this->embeddedfiles[$filename]['f'].' 0 R';
$iconsapp = array('Graph', 'Paperclip', 'PushPin', 'Tag');
if (isset($annot['opt']['name']) && in_array($annot['opt']['name'], $iconsapp)) {
$out .= ' /Name /'.$annot['opt']['name'];
} else {
$out .= ' /Name /PushPin';
}
// index (zero-based) of the annotation in the Annots array of this page
$this->embeddedfiles[$filename]['a'] = $key;
if (!isset($this->embeddedfiles[$filename]['f'])) {
return '';
}
$out = ' /FS '.$this->embeddedfiles[$filename]['f'].' 0 R';
$iconsapp = array('Graph', 'Paperclip', 'PushPin', 'Tag');
if (isset($annot['opt']['name']) && in_array($annot['opt']['name'], $iconsapp)) {
$out .= ' /Name /'.$annot['opt']['name'];
} else {
$out .= ' /Name /PushPin';
}
// index (zero-based) of the annotation in the Annots array of this page
$this->embeddedfiles[$filename]['a'] = $key;
return $out;
}

Expand All @@ -1611,19 +1612,20 @@ protected function getOutAnnotationOptSubtypeSound($annot)
{
$out = '';
if (empty($annot['opt']['fs'])) {
return $out;
return '';
}
$filename = basename($annot['opt']['fs']);
if (isset($this->embeddedfiles[$filename]['f'])) {
// ... TO BE COMPLETED ...
// /R /C /B /E /CO /CP
$out .= ' /Sound '.$this->embeddedfiles[$filename]['f'].' 0 R';
$iconsapp = array('Speaker', 'Mic');
if (isset($annot['opt']['name']) && in_array($annot['opt']['name'], $iconsapp)) {
$out .= ' /Name /'.$annot['opt']['name'];
} else {
$out .= ' /Name /Speaker';
}
if (!isset($this->embeddedfiles[$filename]['f'])) {
return '';
}
// ... TO BE COMPLETED ...
// /R /C /B /E /CO /CP
$out = ' /Sound '.$this->embeddedfiles[$filename]['f'].' 0 R';
$iconsapp = array('Speaker', 'Mic');
if (isset($annot['opt']['name']) && in_array($annot['opt']['name'], $iconsapp)) {
$out .= ' /Name /'.$annot['opt']['name'];
} else {
$out .= ' /Name /Speaker';
}
return $out;
}
Expand Down Expand Up @@ -1726,9 +1728,9 @@ protected function getOutAnnotationOptSubtypeWidget($annot, $oid)
$out .= '>>';
}
// --- Entries for field dictionaries ---
if (isset($this->radiobuttonGroups[$n][$annot['txt']])) {
if (isset($this->radiobuttonGroups[$annot['txt']])) {
// set parent
$out .= ' /Parent '.$this->radiobuttonGroups[$n][$annot['txt']].' 0 R';
$out .= ' /Parent '.$this->radiobuttonGroups[$annot['txt']].' 0 R';
}
if (isset($annot['opt']['t']) && is_string($annot['opt']['t'])) {
$out .= ' /T '.$this->encrypt->escapeDataString($annot['opt']['t'], $oid);
Expand Down
81 changes: 81 additions & 0 deletions src/Tcpdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ class Tcpdf extends \Com\Tecnick\Pdf\ClassObjects
*/
protected $embeddedfiles = array();

/**
* Annotations indexed bu object IDs.
*
* @var array
*/
protected $annotation = array();

/**
* Array containing the regular expression used to identify withespaces or word separators.
*
Expand Down Expand Up @@ -355,4 +362,78 @@ public function getBarcode(
$out .= $this->graph->getStopTransform();
return $out;
}

/**
* Convert the input points value to the user units.
*
* @param float $val Value in internal points unit.
*
* @return float Value in user units.
*/
public function pointsToUserUnit($val)
{
return ((float) $val / $this->kunit);
}

/**
* Convert the input value in user unit to internal points.
*
* @param float $val Value in user unit.
*
* @return float Value in internal points.
*/
public function userToPointsUnit($val)
{
return ((float) $val * $this->kunit);
}

/**
* Add an annotation and returns the object id.
*
* @param float $posx Abscissa of upper-left corner.
* @param float $posy Ordinate of upper-left corner.
* @param float $width Width.
* @param float $height Height.
* @param string $txt Annotation text or alternate content.
* @param array $opt Array of options (see section 8.4 of PDF reference 1.7).
* @param int $spaces Number of spaces on the text to link.
*
* @return int Object ID.
*/
public function setAnnotation($posx, $posy, $width, $height, $txt, $opt = array('Subtype'=>'Text'))
{
$oid = ++$this->pon;
$this->annotation[$oid] = array(
'n' => $oid,
'x' => $posx,
'y' => $posy,
'w' => $width,
'h' => $height,
'txt' => $txt,
'opt' => $opt
);
switch (strtolower($opt['subtype'])) {
case 'fileattachment':
case 'sound':
$filekey = basename($opt['fs']);
if (isset($opt['fs']) && empty($this->embeddedfiles[$filekey])) {
$this->embeddedfiles[$filekey] = array(
'f' => ++$this->pon,
'n' => ++$this->pon,
'file' => $opt['fs']
);
}
}
// Add widgets annotation's icons
if (isset($opt['mk']['i'])) {
$pdf->image->add($opt['mk']['i']);
}
if (isset($opt['mk']['ri'])) {
$pdf->image->add($opt['mk']['ri']);
}
if (isset($opt['mk']['ix'])) {
$pdf->image->add($opt['mk']['ix']);
}
return $oid;
}
}
Loading

0 comments on commit 00cec2c

Please sign in to comment.