5
* The PDF:: class provides a PHP-only implementation of a PDF library.
6
* No external libs or PHP extensions are required.
8
* Based on the FPDF class by Olivier Plathey (http://www.fpdf.org) and the
9
* Horde Framework PDF package (http://www.horde.org)
11
* Copyright 2003 Marko Djukic <marko@oblo.com>
12
* Copyright 2003 Olivier Plathey <olivier@fpdf.org>
14
* See the enclosed file COPYING for license information (LGPL). If you did not
15
* receive this file, see http://www.fsf.org/copyleft/lgpl.html.
17
* @author Olivier Plathey <olivier@fpdf.org>
18
* @author Marko Djukic <marko@oblo.com>
20
//include ('class.pdf.php');
21
//include ('fpdf.php');
24
var $_buffer = ''; // Buffer holding in-memory PDF.
25
var $_state = 0; // Current document state.
26
var $_page = 0; // Current page number.
27
var $_n = 2; // Current object number.
28
var $_offsets = array(); // Array of object offsets.
29
var $_pages = array(); // Array containing the pages.
30
var $_w; // Page width in points.
31
var $_h; // Page height in points
32
var $_fonts = array(); // An array of used fonts.
33
var $_font_family = ''; // Current font family.
34
var $_font_style = ''; // Current font style.
35
var $_current_font; // Array with current font info.
36
var $_font_size = 12; // Current font size in points.
37
var $_compress; // Flag to compress or not.
38
var $_core_fonts = array('courier' => 'Courier',
39
'courierB' => 'Courier-Bold',
40
'courierI' => 'Courier-Oblique',
41
'courierBI' => 'Courier-BoldOblique',
42
'helvetica' => 'Helvetica',
43
'helveticaB' => 'Helvetica-Bold',
44
'helveticaI' => 'Helvetica-Oblique',
45
'helveticaBI' => 'Helvetica-BoldOblique',
46
'times' => 'Times-Roman',
47
'timesB' => 'Times-Bold',
48
'timesI' => 'Times-Italic',
49
'timesBI' => 'Times-BoldItalic',
51
'zapfdingbats' => 'ZapfDingbats');
52
var $_fill_color = '0 g'; // Color used on text and fills.
53
var $_draw_color = '0 G'; // Line draw color.
54
var $_line_width = 1; // Drawing line width.
55
var $_images = array(); // An array of used images.
58
* Attempts to return a conrete PDF instance. It allows to set up the page
59
* format, the orientation and the units of measurement used in all the
60
* methods (except for the font sizes).
63
* $pdf = &PDF::factory('P', 'A4');
67
* @param optional string $orientation Default page orientation.
68
* Possible values are (case
70
* - P or Portrait (default)
72
* @param optional mixed format The format used for pages. It can
73
* be either one of the following
74
* values (case insensitive):
80
* or a custom format in the form of
81
* a two-element array containing the
82
* width and the height (expressed in
83
* the unit given by unit).
85
function &factory($orientation = 'P', $format = 'A4')
87
/* Create the PDF object. */
91
$format = strtolower($format);
92
if ($format == 'a3') { // A3 page size.
93
$format = array(841.89, 1190.55);
94
} elseif ($format == 'a4') { // A4 page size.
95
$format = array(595.28, 841.89);
96
} elseif ($format == 'a5') { // A5 page size.
97
$format = array(420.94, 595.28);
98
} elseif ($format == 'letter') { // Letter page size.
99
$format = array(612, 792);
100
} elseif ($format == 'legal') { // Legal page size.
101
$format = array(612, 1008);
103
die(sprintf('Unknown page format: %s', $format));
105
$pdf->_w = $format[0];
106
$pdf->_h = $format[1];
108
/* Page orientation. */
109
$orientation = strtolower($orientation);
110
if ($orientation == 'l' || $orientation == 'landscape') {
114
} elseif ($orientation != 'p' && $orientation != 'portrait') {
115
die(sprintf('Incorrect orientation: %s', $orientation));
118
/* Turn on compression by default. */
119
$pdf->setCompression(true);
125
* Activates or deactivates page compression. When activated, the internal
126
* representation of each page is compressed, which leads to a compression
127
* ratio of about 2 for the resulting document.
128
* Compression is on by default.
129
* Note: the Zlib extension is required for this feature. If not present,
130
* compression will be turned off.
132
* @param bool $compress Boolean indicating if compression must be
135
function setCompression($compress)
137
/* If no gzcompress function is available then default to
139
$this->_compress = (function_exists('gzcompress') ? $compress : false);
143
* This method begins the generation of the PDF document; it must be
144
* called before any output commands. No page is created by this method,
145
* therefore it is necessary to call PDF::addPage.
151
$this->_state = 1; // Set state to initialised.
152
$this->_out('%PDF-1.3'); // Output the PDF header.
156
* Adds a new page to the document. The font which was set before calling
157
* is automatically restored. There is no need to call PDF::setFont again
158
* if you want to continue with the same font.
164
$this->_page++; // Increment page count.
165
$this->_pages[$this->_page] = ''; // Start the page buffer.
166
$this->_state = 2; // Set state to page
168
/* Check if font has been set before this page. */
169
if ($this->_font_family) {
170
$this->setFont($this->_font_family, $this->_font_style, $this->_font_size);
172
/* Check if fill color has been set before this page. */
173
if ($this->_fill_color != '0 g') {
174
$this->_out($this->_fill_color);
176
/* Check if draw color has been set before this page. */
177
if ($this->_draw_color != '0 G') {
178
$this->_out($this->_draw_color);
180
/* Check if line width has been set before this page. */
181
if ($this->_line_width != 1) {
182
$this->_out($this->_line_width);
187
* Sets the font used to print character strings. It is mandatory to call
188
* this method at least once before printing text or the resulting
189
* document would not be valid. The font must be a standard one. Standard
190
* fonts use Windows encoding cp1252 (Western Europe).
191
* The method can be called before the first page is created and the font
192
* is retained from page to page.
193
* If you just wish to change the current font size, it is simpler to call
198
* @param string $family Family font. It must be one of the
199
* standard families (case insensitive):
200
* - Courier (fixed-width)
201
* - Helvetica or Arial (sans serif)
203
* - Symbol (symbolic)
204
* - ZapfDingbats (symbolic)
205
* It is also possible to pass an empty
206
* string. In that case, the current
207
* family is retained.
208
* @param optional string $style Font style. Possible values are (case
210
* - empty string: regular
213
* or any combination. The default value is
214
* regular. Bold and italic styles do not
215
* apply to Symbol and ZapfDingbats.
216
* @param optional int $size Font size in points. The default value
217
* is the current size. If no size has been
218
* specified since the beginning of the
219
* document, the value taken is 12.
221
function setFont($family, $style = '', $size = null)
223
$family = strtolower($family);
224
if ($family == 'arial') { // Use helvetica.
225
$family = 'helvetica';
226
} elseif ($family == 'symbol' || // No styles for
227
$family == 'zapfdingbats') { // these two fonts.
231
$style = strtoupper($style);
232
if ($style == 'IB') { // Accept any order
233
$style = 'BI'; // of B and I.
236
if (is_null($size)) { // No size specified,
237
$size = $this->_font_size; // use current size.
240
if ($this->_font_family == $family && // If font is already
241
$this->_font_style == $style && // current font
242
$this->_font_size == $size) { // simply return.
246
/* Set the font key. */
247
$fontkey = $family . $style;
249
if (!isset($this->_fonts[$fontkey])) { // Test if cached.
250
$i = count($this->_fonts) + 1; // Increment font
251
$this->_fonts[$fontkey] = array( // object count and
252
'i' => $i, // store cache.
253
'name' => $this->_core_fonts[$fontkey]);
256
/* Store current font information. */
257
$this->_font_family = $family;
258
$this->_font_style = $style;
259
$this->_font_size = $size;
260
$this->_current_font = $this->_fonts[$fontkey];
262
/* Output font information if at least one page has been
264
if ($this->_page > 0) {
265
$this->_out(sprintf('BT /F%d %.2f Tf ET', $this->_current_font['i'], $this->_font_size));
270
* Defines the size of the current font.
274
* @param float $size The size (in points).
276
function setFontSize($size)
278
if ($this->_font_size == $size) { // If already current
279
return; // size simply return.
282
$this->_font_size = $size; // Set the font.
284
/* Output font information if at least one page has been
286
if ($this->_page > 0) {
287
$this->_out(sprintf('BT /F%d %.2f Tf ET',
288
$this->_current_font['i'],
294
* Sets the fill color. Specifies the color for both filled areas and
295
* text. Depending on the colorspace called, the number of color component
296
* parameters required can be either 1, 3 or 4. The method can be called
297
* before the first page is created and the color is retained from page to
302
* @param string $cs Indicates the colorspace which can be either
303
* 'rgb', 'cmyk' or 'gray'. Defaults to 'rgb'.
304
* @param float $c1 First color component, floating point value
305
* between 0 and 1. Required for gray, rgb and
307
* @param optional float $c2 Second color component, floating point value
308
* between 0 and 1. Required for rgb and cmyk.
309
* @param optional float $c3 Third color component, floating point value
310
* between 0 and 1. Required for rgb and cmyk.
311
* @param optional float $c4 Fourth color component, floating point value
312
* between 0 and 1. Required for cmyk.
314
function setFillColor($cs = 'rgb', $c1, $c2 = 0, $c3 = 0, $c4 = 0)
316
$cs = strtolower($cs);
318
/* Using a three component RGB color. */
319
$this->_fill_color = sprintf('%.3f %.3f %.3f rg',
321
} elseif ($cs = 'cmyk') {
322
/* Using a four component CMYK color. */
323
$this->_fill_color = sprintf('%.3f %.3f %.3f %.3f k',
326
/* Grayscale one component color. */
327
$this->_fill_color = sprintf('%.3f g', $c1);
329
/* If document started output to buffer. */
330
if ($this->_page > 0) {
331
$this->_out($this->_fill_color);
336
* Sets the draw color, used when drawing lines. Depending on the
337
* colorspace called, the number of color component parameters required
338
* can be either 1, 3 or 4. The method can be called before the first page
339
* is created and the color is retained from page to page.
343
* @param string $cs Indicates the colorspace which can be either
344
* 'rgb', 'cmyk' or 'gray'. Defaults to 'rgb'.
345
* @param float $c1 First color component, floating point value
346
* between 0 and 1. Required for gray, rgb and
348
* @param optional float $c2 Second color component, floating point value
349
* between 0 and 1. Required for rgb and cmyk.
350
* @param optional float $c3 Third color component, floating point value
351
* between 0 and 1. Required for rgb and cmyk.
352
* @param optional float $c4 Fourth color component, floating point value
353
* between 0 and 1. Required for cmyk.
355
function setDrawColor($cs = 'rgb', $c1, $c2 = 0, $c3 = 0, $c4 = 0)
357
$cs = strtolower($cs);
359
$this->_draw_color = sprintf('%.3f %.3f %.3f RG',
361
} elseif ($cs = 'cmyk') {
362
$this->_draw_color = sprintf('%.3f %.3f %.3f %.3f K',
365
$this->_draw_color = sprintf('%.3f G', $c1);
367
/* If document started output to buffer. */
368
if ($this->_page > 0) {
369
$this->_out($this->_draw_color);
374
* Defines the line width. By default, the value equals 1 pt. The method
375
* can be called before the first page is created and the value is
376
* retained from page to page.
380
* @param float $width The width.
382
function setLineWidth($width)
384
$this->_line_width = $width;
385
if ($this->_page > 0) {
386
$this->_out(sprintf('%.2f w', $width));
391
* Prints a character string. The origin is on the left of the first
392
* character, on the baseline. This method allows to place a string
393
* precisely on the page.
397
* @param float $x Abscissa of the origin.
398
* @param float $y Ordinate of the origin.
399
* @param string $text String to print.
401
function text($x, $y, $text)
403
$text = $this->_escape($text); // Escape any harmful
406
$out = sprintf('BT %.2f %.2f Td (%s) Tj ET',
407
$x, $this->_h - $y, $text);
412
* Prints an image in the page. The upper-left corner and at least one of
413
* the dimensions must be specified; the height or the width can be
414
* calculated automatically in order to keep the image proportions.
415
* Supported format is JPEG.
417
* For JPEG, all flavors are allowed:
419
* - true colors (24 bits)
422
* The format will be inferred from the file extension.
424
* Remark: if an image is used several times, only one copy will be
425
* embedded in the file.
429
* @param string $file Name of the file containing the image.
430
* @param float $x Abscissa of the upper-left corner.
431
* @param float $y Ordinate of the upper-left corner.
432
* @param float $width Width of the image in the page. If equal
433
* to zero, it is automatically calculated
434
* to keep the original proportions.
435
* @param optional float $height Height of the image in the page. If not
436
* specified or equal to zero, it is
437
* automatically calculated to keep the
438
* original proportions.
440
function image($file, $x, $y, $width = 0, $height = 0)
442
if (!isset($this->_images[$file])) {
443
/* First use of requested image, get the extension. */
444
if (($pos = strrpos($file, '.')) === false) {
445
die(sprintf('Image file %s has no extension and no type was specified', $file));
447
$type = strtolower(substr($file, $pos + 1));
449
/* Check the image type and parse. */
450
if ($type == 'jpg' || $type == 'jpeg') {
451
$info = $this->_parseJPG($file);
453
die(sprintf('Unsupported image file type: %s', $type));
455
/* Set the image object id. */
456
$info['i'] = count($this->_images) + 1;
457
/* Set image to array. */
459
$this->_images[$file] = $info;
461
$info = $this->_images[$file]; // Known image, retrieve
465
/* If not specified, do automatic width and height
466
* calculations, either setting to original or
467
* proportionally scaling to one or the other given
469
if (empty($width) && empty($height)) {
471
$height = $info['h'];
472
} elseif (empty($width)) {
473
$width = $height * $info['w'] / $info['h'];
474
} elseif (empty($height)) {
475
$height = $width * $info['h'] / $info['w'];
478
$this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', $width, $height, $x, $this->_h - ($y + $height), $info['i']));
482
* Draws a line between two points.
486
* @param float $x1 Abscissa of first point.
487
* @param float $y1 Ordinate of first point.
488
* @param float $x2 Abscissa of second point.
489
* @param float $y2 Ordinate of second point.
492
function line($x1, $y1, $x2, $y2)
494
$this->_out(sprintf('%.2f %.2f m %.2f %.2f l S', $x1, $this->_h - $y1, $x2, $this->_h - $y2));
498
* Outputs a rectangle. It can be drawn (border only), filled (with no
503
* @param float $x Abscissa of upper left corner.
504
* @param float $y Ordinate of upper left corner.
505
* @param float $width Width.
506
* @param float $height Height.
507
* @param optional string $style Style of rendering. Possible values are:
508
* - D or empty string: draw (default)
510
* - DF or FD: draw and fill
512
function rect($x, $y, $width, $height, $style = '')
514
$style = strtolower($style);
516
$op = 'f'; // Style is fill only.
517
} elseif ($style == 'fd' || $style == 'df') {
518
$op = 'B'; // Style is fill and stroke.
520
$op = 'S'; // Style is stroke only.
523
$this->_out(sprintf('%.2f %.2f %.2f %.2f re %s', $x, $this->_h - $y, $width, -$height, $op));
527
* Outputs a circle. It can be drawn (border only), filled (with no
532
* @param float $x Abscissa of the center of the circle.
533
* @param float $y Ordinate of the center of the circle.
534
* @param float $r Circle radius.
535
* @param optional string $style Style of rendering. Possible values are:
536
* - D or empty string: draw (default)
538
* - DF or FD: draw and fill
540
function circle($x, $y, $r, $style = '')
542
$style = strtolower($style);
544
$op = 'f'; // Style is fill only.
545
} elseif ($style == 'fd' || $style == 'df') {
546
$op = 'B'; // Style is fill and stroke.
548
$op = 'S'; // Style is stroke only.
551
$y = $this->_h - $y; // Adjust y value.
552
$b = $r * 0.552; // Length of the Bezier
554
/* Move from the given origin and set the current point
555
* to the start of the first Bezier curve. */
556
$c = sprintf('%.2f %.2f m', $x - $r, $y);
558
/* First circle quarter. */
559
$c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c',
560
$x, $y + $b, // First control point.
561
$x + $r - $b, $y + $r, // Second control point.
562
$x + $r, $y + $r); // Final point.
563
/* Set x/y to the final point. */
566
/* Second circle quarter. */
567
$c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c',
569
$x + $r, $y - $r + $b,
571
/* Set x/y to the final point. */
574
/* Third circle quarter. */
575
$c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c',
577
$x - $r + $b, $y - $r,
579
/* Set x/y to the final point. */
582
/* Fourth circle quarter. */
583
$c .= sprintf(' %.2f %.2f %.2f %.2f %.2f %.2f c %s',
585
$x - $r, $y + $r - $b,
588
/* Output the whole string. */
593
* Terminates the PDF document. It is not necessary to call this method
594
* explicitly because PDF::output does it automatically.
595
* If the document contains no page, PDF::addPage is called to prevent
596
* from getting an invalid document.
602
if ($this->_page == 0) { // If not yet initialised, add
603
$this->addPage(); // one page to make this a valid
606
$this->_state = 1; // Set the state page closed.
608
/* Pages and resources. */
610
$this->_putResources();
612
/* Print some document info. */
615
$this->_out('/Producer (My First PDF Class)');
616
$this->_out(sprintf('/CreationDate (D:%s)',
619
$this->_out('endobj');
624
$this->_out('/Type /Catalog');
625
$this->_out('/Pages 1 0 R');
626
$this->_out('/OpenAction [3 0 R /FitH null]');
627
$this->_out('/PageLayout /OneColumn');
629
$this->_out('endobj');
631
/* Print cross reference. */
632
$start_xref = strlen($this->_buffer); // Get the xref offset.
633
$this->_out('xref'); // Announce the xref.
634
$this->_out('0 ' . ($this->_n + 1)); // Number of objects.
635
$this->_out('0000000000 65535 f ');
636
/* Loop through all objects and output their offset. */
637
for ($i = 1; $i <= $this->_n; $i++) {
638
$this->_out(sprintf('%010d 00000 n ', $this->_offsets[$i]));
642
$this->_out('trailer');
644
/* The total number of objects. */
645
$this->_out('/Size ' . ($this->_n + 1));
646
/* The root object. */
647
$this->_out('/Root ' . $this->_n . ' 0 R');
648
/* The document information object. */
649
$this->_out('/Info ' . ($this->_n - 1) . ' 0 R');
651
$this->_out('startxref');
652
$this->_out($start_xref); // Where to find the xref.
653
$this->_out('%%EOF');
654
$this->_state = 3; // Set the document state to
659
* Function to output the buffered data to the browser.
663
function output($filename)
665
if ($this->_state < 3) { // If document not yet closed
666
$this->close(); // close it now.
669
/* Make sure no content already sent. */
670
if (headers_sent()) {
671
die('Unable to send PDF file, some data has already been output to browser.');
674
/* Offer file for download and do some browser checks
675
* for correct download. */
676
$agent = trim($_SERVER['HTTP_USER_AGENT']);
677
if ((preg_match('|MSIE ([0-9.]+)|', $agent, $version)) ||
678
(preg_match('|Internet Explorer/([0-9.]+)|', $agent, $version))) {
679
header('Content-Type: application/x-msdownload');
680
Header('Content-Length: ' . strlen($this->_buffer));
681
if ($version == '5.5') {
682
header('Content-Disposition: filename="' . $filename . '"');
684
header('Content-Disposition: attachment; filename="' . $filename . '"');
687
Header('Content-Type: application/pdf');
688
Header('Content-Length: ' . strlen($this->_buffer));
689
Header('Content-disposition: attachment; filename=' . $filename);
696
if ($this->_state == 2) {
697
$this->_pages[$this->_page] .= $s . "\n";
699
$this->_buffer .= $s . "\n";
705
$s = str_replace('\\', '\\\\', $s); // Escape any '\\'
706
$s = str_replace('(', '\\(', $s); // Escape any '('
707
return str_replace(')', '\\)', $s); // Escape any ')'
713
/* Increment the object count. */
715
/* Save the byte offset of this object. */
716
$this->_offsets[$this->_n] = strlen($this->_buffer);
717
/* Output to buffer. */
718
$this->_out($this->_n . ' 0 obj');
723
/* If compression is required set the compression tag. */
724
$filter = ($this->_compress) ? '/Filter /FlateDecode ' : '';
725
/* Print out pages, loop through each. */
726
for ($n = 1; $n <= $this->_page; $n++) {
727
$this->_newobj(); // Start a new object.
728
$this->_out('<</Type /Page'); // Object type.
729
$this->_out('/Parent 1 0 R');
730
$this->_out('/Resources 2 0 R');
731
$this->_out('/Contents ' . ($this->_n + 1) . ' 0 R>>');
732
$this->_out('endobj');
734
/* If compression required gzcompress() the page content. */
735
$p = ($this->_compress) ? gzcompress($this->_pages[$n]) : $this->_pages[$n];
737
/* Output the page content. */
738
$this->_newobj(); // Start a new object.
739
$this->_out('<<' . $filter . '/Length ' . strlen($p) . '>>');
740
$this->_putStream($p); // Output the page.
741
$this->_out('endobj');
744
/* Set the offset of the first object. */
745
$this->_offsets[1] = strlen($this->_buffer);
746
$this->_out('1 0 obj');
747
$this->_out('<</Type /Pages');
749
for ($i = 0; $i < $this->_page; $i++) {
750
$kids .= (3 + 2 * $i) . ' 0 R ';
752
$this->_out($kids . ']');
753
$this->_out('/Count ' . $this->_page);
754
/* Output the page size. */
755
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',
756
$this->_w, $this->_h));
758
$this->_out('endobj');
761
function _putStream($s)
763
$this->_out('stream');
765
$this->_out('endstream');
768
function _putResources()
770
$this->_putFonts(); // Output any fonts.
771
$this->_putImages(); // Output any images.
773
/* Resources are always object number 2. */
774
$this->_offsets[2] = strlen($this->_buffer);
775
$this->_out('2 0 obj');
776
$this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
777
$this->_out('/Font <<');
778
foreach ($this->_fonts as $font) {
779
$this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
782
if (count($this->_images)) { // Loop through any images
783
$this->_out('/XObject <<'); // and output the objects.
784
foreach ($this->_images as $image) {
785
$this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
790
$this->_out('endobj');
795
/* Print out font details. */
796
foreach ($this->_fonts as $k => $font) {
798
$this->_fonts[$k]['n'] = $this->_n;
799
$name = $font['name'];
800
$this->_out('<</Type /Font');
801
$this->_out('/BaseFont /' . $name);
802
$this->_out('/Subtype /Type1');
803
if ($name != 'Symbol' && $name != 'ZapfDingbats') {
804
$this->_out('/Encoding /WinAnsiEncoding');
807
$this->_out('endobj');
811
function _putImages()
813
/* Output any images. */
814
$filter = ($this->_compress) ? '/Filter /FlateDecode ' : '';
815
foreach ($this->_images as $file => $info) {
817
$this->_images[$file]['n'] = $this->_n;
818
$this->_out('<</Type /XObject');
819
$this->_out('/Subtype /Image');
820
$this->_out('/Width ' . $info['w']); // Image width.
821
$this->_out('/Height ' . $info['h']); // Image height.
822
$this->_out('/ColorSpace /' . $info['cs']); //Colorspace
823
if ($info['cs'] == 'DeviceCMYK') {
824
$this->_out('/Decode [1 0 1 0 1 0 1 0]');
826
$this->_out('/BitsPerComponent ' . $info['bpc']); // Bits
827
$this->_out('/Filter /' . $info['f']); // Filter used.
828
$this->_out('/Length ' . strlen($info['data']) . '>>');
829
$this->_putStream($info['data']); // Image data.
830
$this->_out('endobj');
834
function _parseJPG($file)
836
/* Extract info from the JPEG file. */
837
$img = @getimagesize($file);
839
die(sprintf('Missing or incorrect image file: %s', $file));
842
/* Check if dealing with an actual JPEG. */
844
die(sprintf('Not a JPEG file: %s', $file));
846
/* Get the image colorspace. */
847
if (!isset($img['channels']) || $img['channels'] == 3) {
848
$colspace = 'DeviceRGB';
849
} elseif ($img['channels'] == 4) {
850
$colspace = 'DeviceCMYK';
852
$colspace = 'DeviceGray';
854
$bpc = isset($img['bits']) ? $img['bits'] : 8;
856
/* Read the whole file. */
857
$f = fopen($file, 'rb');
858
$data = fread($f, filesize($file));
861
return array('w' => $img[0], 'h' => $img[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data);
865
function AcceptPageBreak()
867
//Accept automatic page break or not
868
return $this->AutoPageBreak;
871
function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='')
875
if($this->y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak())
877
//Automatic page break
885
$this->AddPage($this->CurOrientation);
890
$this->_out(sprintf('%.3f Tw',$ws*$k));
894
$w=$this->w-$this->rMargin-$this->x;
896
if($fill==1 or $border==1)
899
$op=($border==1) ? 'B' : 'f';
902
$s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
904
if(is_string($border))
908
if(is_int(strpos($border,'L')))
909
$s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
910
if(is_int(strpos($border,'T')))
911
$s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
912
if(is_int(strpos($border,'R')))
913
$s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
914
if(is_int(strpos($border,'B')))
915
$s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
920
$dx=$w-$this->cMargin-$this->GetStringWidth($txt);
922
$dx=($w-$this->GetStringWidth($txt))/2;
926
$s.='q '.$this->TextColor.' ';
927
$txt2=str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt)));
928
$s.=sprintf('BT %.2f %.2f Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2);
930
$s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);
934
$this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link);
944
$this->x=$this->lMargin;
950
function MultiCell($w,$h,$txt,$border=0,$align='J',$fill=0)
952
//Output text with automatic or explicit line breaks
953
$cw=&$this->CurrentFont['cw'];
955
$w=$this->w-$this->rMargin-$this->x;
956
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
957
$s=str_replace("\r",'',$txt);
959
if($nb>0 and $s[$nb-1]=="\n")
973
if(is_int(strpos($border,'L')))
975
if(is_int(strpos($border,'R')))
977
$b=is_int(strpos($border,'T')) ? $b2.'T' : $b2;
992
//Explicit line break
998
$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
1005
if($border and $nl==2)
1018
//Automatic line break
1026
$this->_out('0 Tw');
1028
$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
1034
$this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
1035
$this->_out(sprintf('%.3f Tw',$this->ws*$this->k));
1037
$this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
1045
if($border and $nl==2)
1055
$this->_out('0 Tw');
1057
if($border and is_int(strpos($border,'B')))
1059
$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
1060
$this->x=$this->lMargin;
1064
function addTextWrap($xb, $yb, $w, $h, $text, $align='J', $border=0, $fill=0) {
1065
$txt = html_entity_decode($text);
1067
$this->y = $this->h - $yb - $h;
1071
$align = 'R'; break;
1073
$align = 'C'; break;
1078
$this->SetFontSize($h);
1079
$cw=&$this->CurrentFont['cw'];
1081
$w=$this->w-$this->rMargin-$this->x;
1083
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
1084
$s=str_replace("\r",'',$text);
1085
$s=str_replace("\n",' ',$s);
1096
if(is_int(strpos($border,'L'))) {
1099
if(is_int(strpos($border,'R'))) {
1102
$b=is_int(strpos($border,'T')) ? $b2.'T' : $b2;
1113
if($c==' ' AND $i>0) {
1129
$this->_out('0 Tw');
1134
$this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
1135
$this->_out(sprintf('%.3f Tw',$this->ws*$this->k));
1139
$this->Cell($w,$h,substr($s,0,$sep),$b,2,$align,$fill);
1140
$this->x=$this->lMargin;
1142
return substr($s,$sep);