Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.12% covered (success)
94.12%
32 / 34
90.91% covered (success)
90.91%
10 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Font
94.12% covered (success)
94.12%
32 / 34
90.91% covered (success)
90.91%
10 / 11
19.07
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 standardFonts
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setFont
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 getFont
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isStandard
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isEmbedded
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStandardFonts
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getParsedFont
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getStringWidth
85.71% covered (success)
85.71%
12 / 14
0.00% covered (danger)
0.00%
0 / 1
5.07
 parser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Pdf\Document;
15
16use Pop\Pdf\Build\Font\AbstractFont;
17use Pop\Pdf\Build\Font\Parser;
18
19/**
20 * Pdf font class
21 *
22 * @category   Pop
23 * @package    Pop\Pdf
24 * @author     Nick Sagona, III <dev@nolainteractive.com>
25 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
26 * @license    http://www.popphp.org/license     New BSD License
27 * @version    4.2.0
28 */
29class Font
30{
31
32    /**
33     * Standard font constants
34     */
35    const ARIAL                      = 'Arial';
36    const ARIAL_ITALIC               = 'Arial,Italic';
37    const ARIAL_BOLD                 = 'Arial,Bold';
38    const ARIAL_BOLD_ITALIC          = 'Arial,BoldItalic';
39    const COURIER                    = 'Courier';
40    const COURIER_OBLIQUE            = 'Courier-Oblique';
41    const COURIER_BOLD               = 'Courier-Bold';
42    const COURIER_BOLD_OBLIQUE       = 'Courier-BoldOblique';
43    const COURIER_NEW                = 'CourierNew';
44    const COURIER_NEW_ITALIC         = 'CourierNew,Italic';
45    const COURIER_NEW_BOLD           = 'CourierNew,Bold';
46    const COURIER_NEW_BOLD_ITALIC    = 'CourierNew,BoldItalic';
47    const HELVETICA                  = 'Helvetica';
48    const HELVETICA_OBLIQUE          = 'Helvetica-Oblique';
49    const HELVETICA_BOLD             = 'Helvetica-Bold';
50    const HELVETICA_BOLD_OBLIQUE     = 'Helvetica-BoldOblique';
51    const SYMBOL                     = 'Symbol';
52    const TIMES_ROMAN                = 'Times-Roman';
53    const TIMES_BOLD                 = 'Times-Bold';
54    const TIMES_ITALIC               = 'Times-Italic';
55    const TIMES_BOLD_ITALIC          = 'Times-BoldItalic';
56    const TIMES_NEW_ROMAN            = 'TimesNewRoman';
57    const TIMES_NEW_ROMAN_ITALIC     = 'TimesNewRoman,Italic';
58    const TIMES_NEW_ROMAN_BOLD       = 'TimesNewRoman,Bold';
59    const TIMES_NEW_ROMAN_BOLDITALIC = 'TimesNewRoman,BoldItalic';
60    const ZAPF_DINGBATS              = 'ZapfDingbats';
61
62    /**
63     * Standard PDF fonts
64     * @var array
65     */
66    protected $standardFonts = [
67        'Arial', 'Arial,Italic', 'Arial,Bold', 'Arial,BoldItalic', 'Courier', 'CourierNew', 'Courier-Oblique',
68        'CourierNew,Italic', 'Courier-Bold', 'CourierNew,Bold', 'Courier-BoldOblique', 'CourierNew,BoldItalic',
69        'Helvetica', 'Helvetica-Oblique', 'Helvetica-Bold', 'Helvetica-BoldOblique', 'Symbol', 'Times-Roman',
70        'Times-Bold', 'Times-Italic', 'Times-BoldItalic', 'TimesNewRoman', 'TimesNewRoman,Italic',
71        'TimesNewRoman,Bold', 'TimesNewRoman,BoldItalic', 'ZapfDingbats'
72    ];
73
74    /**
75     * Font
76     * @var string
77     */
78    protected $font = null;
79
80    /**
81     * Font name
82     * @var string
83     */
84    protected $name = null;
85
86    /**
87     * Flag for a standard font
88     * @var boolean
89     */
90    protected $isStandard = false;
91
92    /**
93     * Flag for an embedded font file
94     * @var boolean
95     */
96    protected $isEmbedded = false;
97
98    /**
99     * Font parser
100     * @var Parser
101     */
102    protected $parser = null;
103
104    /**
105     * Constructor
106     *
107     * Instantiate a PDF font.
108     *
109     * @param  string $font
110     */
111    public function __construct($font = null)
112    {
113        if (null !== $font) {
114            $this->setFont($font);
115        }
116    }
117
118    /**
119     * Get standard PDF fonts in an array
120     *
121     * @return array
122     */
123    public static function standardFonts()
124    {
125        return (new self())->getStandardFonts();
126    }
127
128    /**
129     * Set font
130     *
131     * @param  string $font
132     * @throws \InvalidArgumentException
133     * @return Font
134     */
135    public function setFont($font)
136    {
137        $this->font = $font;
138        if (in_array($font, $this->standardFonts)) {
139            $this->isStandard = true;
140            $this->name       = $font;
141        } else if (file_exists($font)) {
142            $this->isEmbedded = true;
143            $this->parser     = new Parser($this->font);
144            $this->name       = $this->parser->getFontName();
145        } else {
146            throw new \InvalidArgumentException(
147                "Error: The font '" . $font . "' is not valid. It must be a standard PDF font or a font file."
148            );
149        }
150
151        return $this;
152    }
153
154    /**
155     * Get font
156     *
157     * @return string
158     */
159    public function getFont()
160    {
161        return $this->font;
162    }
163
164    /**
165     * Get font name
166     *
167     * @return string
168     */
169    public function getName()
170    {
171        return $this->name;
172    }
173
174    /**
175     * Determine if the font is a standard font
176     *
177     * @return boolean
178     */
179    public function isStandard()
180    {
181        return $this->isStandard;
182    }
183
184    /**
185     * Determine if the font is an embedded font
186     *
187     * @return boolean
188     */
189    public function isEmbedded()
190    {
191        return $this->isEmbedded;
192    }
193
194    /**
195     * Get available standard fonts
196     *
197     * @return array
198     */
199    public function getStandardFonts()
200    {
201        return $this->standardFonts;
202    }
203
204    /**
205     * Get the font parser
206     *
207     * @return AbstractFont
208     */
209    public function getParsedFont()
210    {
211        return (null !== $this->parser) ? $this->parser->getFont() : null;
212    }
213
214    /**
215     * Attempt to get string width
216     *
217     * @param  string $string
218     * @param  mixed  $size
219     * @throws Exception
220     * @return mixed
221     */
222    public function getStringWidth($string, $size)
223    {
224        if (null !== $this->parser) {
225            return $this->parser->getFont()->getStringWidth($string, $size);
226        } else {
227            $fontClass = '\Pop\Pdf\Build\Font\Standard\\' . str_replace([',', '-'], ['', ''], $this->name);
228            if (!class_exists($fontClass)) {
229                throw new Exception('Error: That standard font class was not found.');
230            }
231            $font      = new $fontClass();
232            $widths    = [];
233
234            $drawingString = iconv('UTF-8', 'UTF-16BE//IGNORE', $string);
235            $characters    = [];
236
237            for ($i = 0; $i < strlen($drawingString); $i++) {
238                $characters[] = (ord($drawingString[$i++]) << 8 ) | ord($drawingString[$i]);
239            }
240
241            foreach ($characters as $character) {
242                $widths[] = $font->getGlyphWidth($character);
243            }
244
245            return (array_sum($widths) / $font->getUnitsPerEm()) * $size;
246        }
247    }
248
249    /**
250     * Get the font parser
251     *
252     * @return Parser
253     */
254    public function parser()
255    {
256        return $this->parser;
257    }
258
259}