Skip to content

Commit

Permalink
Function to clone a font and more metrics.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolaasuni committed Aug 24, 2024
1 parent 6a725ad commit 6537d65
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 17 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.4.2
2.5.0
103 changes: 87 additions & 16 deletions src/Stack.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
* 'dw': float,
* 'fbbox': array<int, float>,
* 'height': float,
* 'idx': int,
* 'key': string,
* 'maxwidth': float,
* 'midpoint': float,
Expand All @@ -81,6 +82,7 @@
* 'size': float,
* 'spacing': float,
* 'stretching': float,
* 'style': string,
* 'type': string,
* 'up': float,
* 'usize': float,
Expand Down Expand Up @@ -207,17 +209,82 @@ public function insert(
'stretching' => $stretching,
];

return $this->getFontMetric($this->stack[$this->index]);
return $this->getFontMetric($this->index);
}

/**
* Returns the current font data array
* Returns the current font data array.
*
* @return TFontMetric
*/
public function getCurrentFont(): array
{
return $this->getFontMetric($this->stack[$this->index]);
return $this->getFontMetric($this->index);
}

/**
* Returns a clone of the specified font with new parameters.
*
* @param int $objnum Current PDF object number.
* @param ?int $idx Font index. Leave it null to use the current font.
* @param ?string $style Font style.
* Possible values are (case insensitive):
* regular (default)
* B: bold
* I: italic
* U: underline
* D: strikeout (linethrough)
* O: overline
* @param ?int $size Font size in points (set to null to inherit the last font size).
* @param ?float $spacing Extra spacing between characters.
* @param ?float $stretching Horizontal character stretching ratio.
*
* @return TFontMetric
*/
public function cloneFont(
int &$objnum,
?int $idx = null,
?string $style = null,
?int $size = null,
?float $spacing = null,
?float $stretching = null,
): array {
if ($idx === null) {
$idx = $this->index;
} elseif (($idx < 0) || ($idx > $this->index)) {
throw new FontException('Invalid font index');
}

$curfont = $this->stack[$idx];

if (($style === null) || ($style == $curfont['style'])) {
$size = $this->getInputSize($size);
$spacing = $this->getInputSpacing($spacing);
$stretching = $this->getInputStretching($stretching);

$this->stack[++$this->index] = [
'key' => $curfont['key'],
'style' => $curfont['style'],
'size' => $size,
'spacing' => $spacing,
'stretching' => $stretching,
];

return $this->getFontMetric($this->index);
}

$data = $this->getFont($curfont['key']);

return $this->insert(
$objnum,
$data['family'],
$style,
$size,
$spacing,
$stretching,
$data['ifile'],
$data['subset'],
);
}

/**
Expand All @@ -233,7 +300,7 @@ public function getCurrentFontType(): string
*/
public function getOutCurrentFont(): string
{
return $this->getFontMetric($this->stack[$this->index])['out'];
return $this->getFontMetric($this->index)['out'];
}

/**
Expand Down Expand Up @@ -265,9 +332,10 @@ public function popLastFont(): array
throw new FontException('The font stack is empty');
}

$font = array_pop($this->stack);
$font = $this->getFontMetric($this->index);
array_pop($this->stack);
--$this->index;
return $this->getFontMetric($font);
return $font;
}

/**
Expand All @@ -282,7 +350,7 @@ public function popLastFont(): array
*/
public function replaceMissingChars(array $uniarr, array $subs = []): array
{
$font = $this->getFontMetric($this->stack[$this->index]);
$font = $this->getFontMetric($this->index);
foreach ($uniarr as $pos => $uni) {
if (isset($font['cw'][$uni])) {
continue;
Expand Down Expand Up @@ -310,7 +378,7 @@ public function replaceMissingChars(array $uniarr, array $subs = []): array
*/
public function isCharDefined(int $ord): bool
{
$font = $this->getFontMetric($this->stack[$this->index]);
$font = $this->getFontMetric($this->index);
return isset($font['cw'][$ord]);
}

Expand All @@ -327,7 +395,7 @@ public function getCharWidth(int $ord): float
return 0;
}

$font = $this->getFontMetric($this->stack[$this->index]);
$font = $this->getFontMetric($this->index);
return $font['cw'][$ord] ?? $font['dw'];
}

Expand Down Expand Up @@ -407,7 +475,7 @@ public function getOrdArrDims(array $uniarr): array
*/
public function getCharBBox(int $ord): array
{
$font = $this->getFontMetric($this->stack[$this->index]);
$font = $this->getFontMetric($this->index);
return $font['cbbox'][$ord] ?? [0.0, 0.0, 0.0, 0.0]; // glyph without outline
}

Expand Down Expand Up @@ -435,18 +503,19 @@ public function replaceChar(int $oldchar, int $newchar): int
/**
* Returns the font metrics associated to the input key.
*
* @param TStackItem $font Stack item
* @param int $idx Font index in the stack.
*
* @return TFontMetric
*/
protected function getFontMetric(array $font): array
protected function getFontMetric(int $idx): array
{
$font = $this->stack[$idx];
$mkey = md5(serialize($font));
if (! empty($this->metric[$mkey])) {
return $this->metric[$mkey];
}

$size = ($font['size']);
$size = $font['size'];
$usize = ((float) $size / $this->kunit);
$cratio = ((float) $size / 1000);
$wratio = ($cratio * $font['stretching']); // horizontal ratio
Expand All @@ -464,6 +533,7 @@ protected function getFontMetric(array $font): array
'dw' => ((float) $data['dw'] * $cratio * $font['stretching']),
'fbbox' => [],
'height' => ((float) ($data['desc']['Ascent'] - $data['desc']['Descent']) * $cratio),
'idx' => $idx,
'key' => $font['key'],
'maxwidth' => ((float) $data['desc']['MaxWidth'] * $cratio * $font['stretching']),
'midpoint' => ((float) ($data['desc']['Ascent'] + $data['desc']['Descent']) * $cratio / 2),
Expand All @@ -473,6 +543,7 @@ protected function getFontMetric(array $font): array
'size' => $size,
'spacing' => $font['spacing'],
'stretching' => $font['stretching'],
'style' => $font['style'],
'type' => $data['type'],
'up' => ((float) $data['up'] * $cratio),
'usize' => $usize,
Expand Down Expand Up @@ -533,7 +604,7 @@ protected function getInputSize(?int $size = null): float
if (($size === null) || ($size < 0)) {
if ($this->index >= 0) {
// inherit the size of the last inserted font
return $this->stack[$this->index]['size'];
return $this->stack[$this->index]['size'] ?? 0;
}

return self::DEFAULT_SIZE;
Expand All @@ -553,7 +624,7 @@ protected function getInputSpacing(?float $spacing = null): float
if ($spacing === null) {
if ($this->index >= 0) {
// inherit the size of the last inserted font
return $this->stack[$this->index]['spacing'];
return $this->stack[$this->index]['spacing'] ?? 0;
}

return 0;
Expand All @@ -573,7 +644,7 @@ protected function getInputStretching(?float $stretching = null): float
if ($stretching === null) {
if ($this->index >= 0) {
// inherit the size of the last inserted font
return $this->stack[$this->index]['stretching'];
return $this->stack[$this->index]['stretching'] ?? 0;
}

return 1;
Expand Down
11 changes: 11 additions & 0 deletions test/StackTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,17 @@ public function testStack(): void

$outfont = $stack->getOutCurrentFont();
$this->assertEquals("BT /F2 14.000000 Tf ET\r", $outfont);

$font = $stack->cloneFont($objnum, null, null, 13, 0.3, 0.7);
$this->assertEquals(13, $font['size']);
$this->assertEquals(0.3, $font['spacing']);
$this->assertEquals(0.7, $font['stretching']);

$font = $stack->cloneFont($objnum, 0, 'BI', 17, 0.7, 1.3);
$this->assertEquals('BI', $font['style']);
$this->assertEquals(17, $font['size']);
$this->assertEquals(0.7, $font['spacing']);
$this->assertEquals(1.3, $font['stretching']);
}

public function testEmptyStack(): void
Expand Down

0 comments on commit 6537d65

Please sign in to comment.