views/pdfLayouts/IPdfWriter.php
Rama main · réplica de lectura del repositorio original.
<?php
namespace app\views\pdfLayouts;
use app\models\db\MotionSection;
use Com\Tecnick\Pdf\Import\PageTemplateInterface;
class IPdfWriter extends \TCPDF
{
/**
* Replicates the private \TCPDF::engineNew(), wiring in the engine subclass that implements
* Antragsgrün's custom list rendering (see IPdfWriterEngine).
*
* Note: \TCPDF::SetProtection() re-creates the engine through the private engineNew()
* and would silently replace it with the default engine; it must not be used with this class.
*/
protected function engineInit(string $unit): void
{
$unit = strtolower(trim($unit)) === '' ? 'mm' : strtolower(trim($unit));
$this->docunit = $unit;
$eng = new IPdfWriterEngine(
$this->docunit,
$this->unicode,
false,
true,
$this->pdfamode,
null,
$this->fileOptions(),
);
$eng->pagecontexthook = $this->ambientPageContent(...);
$this->eng = $eng;
$this->kratio = $eng->toPoints(1.0);
$css = <<<CSS
blockquote {
margin-left: 9.5mm;
padding-left: 4mm;
border-left: 1mm dotted #cccccc;
color: #444444;
}
CSS;
$this->eng->addGlobalCSS($css);
}
/**
* Registers a PDF given as a binary string as an import source (replaces FPDI's setSourceFile).
*
* @return string the source ID to be passed to the other import methods
*
* @throws \Com\Tecnick\Pdf\Import\ImportException
*/
public function importPdfSource(string $data): string
{
return $this->engine()->setImportSourceData($data);
}
/**
* @throws \Com\Tecnick\Pdf\Import\ImportException
*/
public function getImportedPageCount(string $sourceId): int
{
return $this->engine()->getSourcePageCount($sourceId);
}
/**
* @throws \Com\Tecnick\Pdf\Import\ImportException
*/
public function importPdfPage(string $sourceId, int $pageNo): PageTemplateInterface
{
return $this->engine()->importPage($sourceId, $pageNo);
}
/**
* Returns the size of an imported page in user units (mm).
*
* @return array{width: float, height: float, orientation: string}
*/
public function getImportedPageSize(PageTemplateInterface $page): array
{
$width = $this->engine()->toUnit($page->getWidth());
$height = $this->engine()->toUnit($page->getHeight());
return [
'width' => $width,
'height' => $height,
'orientation' => ($width > $height ? 'L' : 'P'),
];
}
/**
* Places an imported page onto the current page (replaces FPDI's useTemplate).
* Coordinates and sizes are given in user units (mm); if width/height are omitted,
* the original size of the imported page is used.
*/
public function useImportedPage(PageTemplateInterface $page, float $x = 0, float $y = 0, ?float $width = null, ?float $height = null): void
{
$this->engine()->useImportedPage($page, $x, $y, $width, $height);
}
/**
* This adds <br>-tags where necessary.
* Test cases are collected in the "Listen-Test"-motion.
* Check in the TCPDF-generated PDF that line numbers match the lines.
*
* @param string[] $linesArr
*
* @return string[]
*/
private function printMotionToPDFAddLinebreaks(array $linesArr): array
{
for ($i = 1; $i < count($linesArr); $i++) {
// Does this line start with an ol/ul/li?
if (!preg_match('/^<(ol|ul|li)/siu', $linesArr[$i])) {
continue;
}
// Does the previous line end a block element? If not, we need the extra BR
if (!preg_match('/<\/(div|p|blockquote|ul|ol|h1|h2|h3|h4|h5|h6)>$/siu', $linesArr[$i - 1])) {
$linesArr[$i] = '<br>' . $linesArr[$i];
}
}
return $linesArr;
}
public function getMotionFont(?MotionSection $section): string
{
if ($section && $section->getSettings()->fixedWidth) {
return 'dejavusansmono';
} else {
return 'helvetica';
}
}
public function getMotionFontSize(?MotionSection $section): int
{
if ($section) {
$lineLength = $section->getConsultation()->getSettings()->lineLength;
return ($lineLength > 70 ? 10 : 11);
} else {
return 10;
}
}
/**
* Prints the lines of one paragraph of a motion text section, optionally with line numbers on the left.
* The line number column has a width of $lineNumberWidth (starting at $x), the text is printed right next to it.
* If $firstLineNumber is null, no line numbers are printed.
*
* @param string[] $lines
* @return int|null The line number following the last line of this paragraph
*/
public function printMotionParagraphLines(array $lines, ?int $firstLineNumber, float $x, float $lineNumberWidth, float $textWidth, string $fontName, float $textSize): ?int
{
$linesArr = [];
foreach ($lines as $line) {
$line = str_replace('###LINENUMBER###', '', $line);
$line = preg_replace('/<br>\s*$/siu', '', $line);
$linesArr[] = $line . '';
}
// Hint about <li>s: The spacing between list items is created by </li><br><li>-markup.
// This obviously is incorrect according to HTML, but is rendered correctly neverless.
// We just have to take care about additional spacing for the line numbers in these cases.
$linenr = $firstLineNumber;
if ($linenr !== null) {
$lineNos = [];
for ($i = 0; $i < count($lines); $i++) {
if (preg_match('/^<(ul|ol|li)/siu', $linesArr[$i])) {
$lineNos[] = ''; // Just for having an additional <br>
}
$lineNos[] = $linenr++;
}
$text2 = implode('<br>', $lineNos);
} else {
$text2 = '';
}
$page = $this->getPage();
$y = $this->getY();
$this->SetFont($fontName, '', $textSize * 2 / 3);
$this->SetTextColor(100, 100, 100);
$this->setCellHeightRatio(2.23);
$this->writeHTMLCell($lineNumberWidth, 0, $x, $y, $text2, 0, 0, false, true, '', true);
$this->setPage($page);
$this->SetFont($fontName, '', $textSize);
$this->SetTextColor(0, 0, 0);
$this->setCellHeightRatio(1.5);
$linesArr = $this->printMotionToPDFAddLinebreaks($linesArr);
$text1 = implode('<br>', $linesArr);
$text1 = str_replace('</li><br><br><li', '</li><br><li', $text1);
// instead of <span class="strike"></span> TCPDF can only handle <s></s>
// for striking through text
$text1 = preg_replace('/<span class="strike">(.*)<\/span>/iUs', '<s>${1}</s>', $text1);
// instead of <span class="underline"></span> TCPDF can only handle <u></u>
// for underlined text
$text1 = preg_replace('/<span class="underline">(.*)<\/span>/iUs', '<u>${1}</u>', $text1);
$this->writeHTMLCell($textWidth, 0, $x + $lineNumberWidth, $y, $text1, 0, 1, false, true, '', true);
return $linenr;
}
public function printMotionSection(MotionSection $section): void
{
$linenr = $section->getFirstLineNumber();
$textSize = $this->getMotionFontSize($section);
$fontName = $this->getMotionFont($section);
$this->SetFont($fontName, '', $textSize);
$this->Ln(7);
$hasLineNumbers = !!$section->getSettings()->lineNumbers;
if ($section->getSettings()->fixedWidth || $hasLineNumbers) {
$paragraphs = $section->getTextParagraphObjects($hasLineNumbers);
foreach ($paragraphs as $paragraph) {
$linenr = $this->printMotionParagraphLines($paragraph->lines, $hasLineNumbers ? $linenr : null, 12, 12, 173, $fontName, $textSize);
$this->Ln(7);
}
} else {
$paras = $section->getTextParagraphLines();
foreach ($paras as $para) {
$html = str_replace('###LINENUMBER###', '', implode('', $para->lines));
$html = str_replace('</li>', '<br></li>', $html);
$html = str_replace('<ol', '<br><ol', $html);
$html = str_replace('<ul', '<br><ul', $html);
$y = $this->getY();
$this->writeHTMLCell(12, 0, 12, $y, '', 0, 0, false, true, '', true);
$this->writeHTMLCell(173, 0, 24, null, $html, 0, 1, false, true, '', true);
$this->Ln(7);
}
}
}
}