Files
EpiWebview/vendor/tecnickcom/tc-lib-pdf-font/src/Output.php

259 lines
7.5 KiB
PHP

<?php
/**
* Output.php
*
* @since 2011-05-23
* @category Library
* @package PdfFont
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2011-2024 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf-font
*
* This file is part of tc-lib-pdf-font software library.
*/
namespace Com\Tecnick\Pdf\Font;
use Com\Tecnick\Pdf\Encrypt\Encrypt;
use Com\Tecnick\Pdf\Font\Exception as FontException;
/**
* Com\Tecnick\Pdf\Font\Output
*
* @since 2011-05-23
* @category Library
* @package PdfFont
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2011-2024 Nicola Asuni - Tecnick.com LTD
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf-font
*
* @phpstan-import-type TFontData from Load
*/
class Output extends \Com\Tecnick\Pdf\Font\OutFont
{
/**
* Array of character subsets for each font file
*
* @var array<string, array<int, bool>>
*/
protected array $subchars = [];
/**
* PDF string block with the fonts definitions
*/
protected string $out = '';
/**
* Initialize font data
*
* @param array<string, TFontData> $fonts Array of imported fonts data
* @param int $pon Current PDF Object Number
* @param Encrypt $encrypt Encrypt object
*/
public function __construct(
protected array $fonts,
int $pon,
Encrypt $encrypt
) {
$this->pon = $pon;
$this->enc = $encrypt;
$this->out = $this->getEncodingDiffs();
$this->out .= $this->getFontFiles();
$this->out .= $this->getFontDefinitions();
}
/**
* Returns current PDF object number
*/
public function getObjectNumber(): int
{
return $this->pon;
}
/**
* Returns the PDF fonts block
*/
public function getFontsBlock(): string
{
return $this->out;
}
/**
* Get the PDF output string for Font resources dictionary.
*
* @param array<string, array{'i': int, 'n': int}> $data Font data.
*
* @return string
*/
private function getOutFontResources(array $data): string
{
if (empty($data)) {
return '';
}
$out = ' /Font <<';
foreach ($data as $font) {
$out .= ' /F' . $font['i'] . ' ' . $font['n'] . ' 0 R';
}
return $out . ' >>';
}
/**
* Get the PDF output string for Font resources dictionary.
*
* @return string
*/
public function getOutFontDict(): string
{
return $this->getOutFontResources($this->fonts);
}
/**
* Get the PDF output string for XOBject Font resources dictionary.
*
* @param array<string> $keys Array of font keys.
*
* @return string
*/
public function getOutFontDictByKeys(array $keys): string
{
if (empty($keys)) {
return '';
}
$data = [];
foreach ($keys as $key) {
$data[$key] = [
'i' => $this->fonts[$key]['i'],
'n' => $this->fonts[$key]['n'],
];
}
return $this->getOutFontResources($data);
}
/**
* Get the PDF output string for font encoding diffs
*
* return string
*/
protected function getEncodingDiffs(): string
{
$out = '';
$done = []; // store processed items to avoid duplication
foreach ($this->fonts as $fkey => $font) {
if (! empty($font['diff'])) {
$dkey = md5($font['diff']);
if (! isset($done[$dkey])) {
$out .= (++$this->pon) . ' 0 obj' . "\n"
. '<< /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['
. $font['diff'] . '] >>' . "\n"
. 'endobj' . "\n";
$done[$dkey] = $this->pon;
}
$this->fonts[$fkey]['diff_n'] = $done[$dkey];
}
// extract the character subset
if (! empty($font['file'])) {
$file_key = md5($font['file']);
if (empty($this->subchars[$file_key])) {
$this->subchars[$file_key] = $font['subsetchars'];
} else {
$this->subchars[$file_key] = array_merge($this->subchars[$file_key], $font['subsetchars']);
}
}
}
return $out;
}
/**
* Get the PDF output string for font files
*
* return string
*/
protected function getFontFiles(): string
{
$out = '';
$done = []; // store processed items to avoid duplication
foreach ($this->fonts as $fkey => $font) {
if (! empty($font['file'])) {
$dkey = md5($font['file']);
if (! isset($done[$dkey])) {
$fontfile = $this->getFontFullPath($font['dir'], $font['file']);
$font_data = file_get_contents($fontfile);
if ($font_data === false) {
throw new FontException('Unable to read font file: ' . $fontfile);
}
if ($font['subset']) {
$font_data = gzuncompress($font_data);
if ($font_data === false) {
throw new FontException('Unable to uncompress font file: ' . $fontfile);
}
$sub = new Subset($font_data, $font, $this->subchars[md5($font['file'])]);
$font_data = $sub->getSubsetFont();
$font['length1'] = strlen($font_data);
$font_data = gzcompress($font_data);
if ($font_data === false) {
throw new FontException('Unable to compress font file: ' . $fontfile);
}
}
++$this->pon;
$stream = $this->enc->encryptString($font_data, $this->pon);
$out .= $this->pon . ' 0 obj' . "\n"
. '<<'
. ' /Filter /FlateDecode'
. ' /Length ' . strlen($stream)
. ' /Length1 ' . $font['length1'];
$out .= ' /Length2 ' . $font['length2']
. ' /Length3 0';
$out .= ' >> stream' . "\n"
. $stream . "\n"
. 'endstream' . "\n"
. 'endobj' . "\n";
$done[$dkey] = $this->pon;
}
$this->fonts[$fkey]['file_n'] = $done[$dkey];
}
}
return $out;
}
/**
* Get the PDF output string for fonts
*
* return string
*/
protected function getFontDefinitions(): string
{
$out = '';
foreach ($this->fonts as $font) {
$out .= match (strtolower($font['type'])) {
'core' => $this->getCore($font),
'cidfont0' => $this->getCid0($font),
'type1' => $this->getTrueType($font),
'truetype' => $this->getTrueType($font),
'truetypeunicode' => $this->getTrueTypeUnicode($font),
default => throw new FontException('Unsupported font type: ' . $font['type']),
};
}
return $out;
}
}