1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* Generates the PDF version using TCPDF.
|
6
|
*
|
7
|
* This file is included by the print_pdf_tcpdf module and includes the
|
8
|
* functions that interface with the TCPDF library.
|
9
|
*
|
10
|
* @ingroup print
|
11
|
*/
|
12
|
|
13
|
/**
|
14
|
* Implements hook_print_pdf_generate().
|
15
|
*/
|
16
|
function print_pdf_tcpdf_print_pdf_generate($html, $meta, $paper_size = NULL, $page_orientation = NULL) {
|
17
|
global $base_url, $language;
|
18
|
|
19
|
module_load_include('inc', 'print', 'includes/print');
|
20
|
|
21
|
$pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
|
22
|
if (empty($paper_size)) {
|
23
|
$paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
|
24
|
}
|
25
|
if (empty($page_orientation)) {
|
26
|
$page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
|
27
|
}
|
28
|
$images_via_file = variable_get('print_pdf_images_via_file', PRINT_PDF_IMAGES_VIA_FILE_DEFAULT);
|
29
|
|
30
|
if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
|
31
|
$pdf_tool_path = realpath(dirname($pdf_tool[1]));
|
32
|
|
33
|
if (!defined('K_TCPDF_EXTERNAL_CONFIG')) {
|
34
|
define('K_TCPDF_EXTERNAL_CONFIG', TRUE);
|
35
|
}
|
36
|
if (!defined('K_PATH_MAIN')) {
|
37
|
define('K_PATH_MAIN', DRUPAL_ROOT);
|
38
|
}
|
39
|
if (!defined('K_PATH_URL')) {
|
40
|
define('K_PATH_URL', $base_url);
|
41
|
}
|
42
|
if (!defined('K_PATH_FONTS')) {
|
43
|
define('K_PATH_FONTS', $pdf_tool_path . '/fonts/');
|
44
|
}
|
45
|
if (!defined('K_PATH_CACHE')) {
|
46
|
define('K_PATH_CACHE', drupal_realpath('public://print_pdf/print_pdf_tcpdf/cache') . '/');
|
47
|
}
|
48
|
if (!defined('K_PATH_IMAGES')) {
|
49
|
define('K_PATH_IMAGES', '');
|
50
|
}
|
51
|
if (!defined('K_BLANK_IMAGE')) {
|
52
|
define('K_BLANK_IMAGE', $pdf_tool_path . '/images/_blank.png');
|
53
|
}
|
54
|
if (!defined('K_CELL_HEIGHT_RATIO')) {
|
55
|
define('K_CELL_HEIGHT_RATIO', 1.25);
|
56
|
}
|
57
|
if (!defined('K_SMALL_RATIO')) {
|
58
|
define('K_SMALL_RATIO', 2 / 3);
|
59
|
}
|
60
|
}
|
61
|
|
62
|
// Try to use local file access for image files.
|
63
|
$html = _print_access_images_via_file($html, $images_via_file);
|
64
|
|
65
|
// Decode HTML entities in image filenames.
|
66
|
$pattern = "!<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?>!is";
|
67
|
$html = preg_replace_callback($pattern, create_function('$matches', 'return html_entity_decode($matches[0], ENT_QUOTES);'), $html);
|
68
|
// Remove queries from the image URL.
|
69
|
$pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?)(?:%3F|\?)[^\s'\"]+([^>]*?>)!is";
|
70
|
$html = preg_replace($pattern, '$1$2', $html);
|
71
|
|
72
|
$tool_path = DRUPAL_ROOT . '/' . $pdf_tool[1];
|
73
|
if (file_exists($tool_path)) {
|
74
|
require_once $tool_path;
|
75
|
}
|
76
|
else {
|
77
|
watchdog('print_pdf', 'Configured PDF tool does not exist at path: %path', array('%path' => $tool_path), WATCHDOG_ERROR);
|
78
|
throw new Exception("Configured PDF tool does not exist, unable to generate PDF.");
|
79
|
}
|
80
|
module_load_include('inc', 'print_pdf_tcpdf', 'print_pdf_tcpdf.class');
|
81
|
|
82
|
$font = array(
|
83
|
check_plain(variable_get('print_pdf_font_family', PRINT_PDF_TCPDF_FONT_FAMILY_DEFAULT)),
|
84
|
'',
|
85
|
check_plain(variable_get('print_pdf_font_size', PRINT_PDF_TCPDF_FONT_SIZE_DEFAULT)),
|
86
|
);
|
87
|
$orientation = drupal_strtoupper($page_orientation[0]);
|
88
|
|
89
|
// Create new PDF document.
|
90
|
$pdf = new PrintTCPDF($orientation, 'mm', $paper_size, TRUE);
|
91
|
|
92
|
// Set document information.
|
93
|
if (isset($meta['name'])) {
|
94
|
$pdf->SetAuthor(strip_tags($meta['name']));
|
95
|
}
|
96
|
$pdf->SetCreator(variable_get('site_name', 'Drupal'));
|
97
|
$pdf->SetTitle(html_entity_decode($meta['title'], ENT_QUOTES, 'UTF-8'));
|
98
|
$pdf->setPDFVersion('1.6');
|
99
|
$pdf->setFontSubsetting(variable_get('print_pdf_font_subsetting', PRINT_PDF_TCPDF_FONT_SUBSETTING_DEFAULT));
|
100
|
$pdf->setTcpdfLink(FALSE);
|
101
|
|
102
|
if ($language->direction == LANGUAGE_RTL) {
|
103
|
$pdf->setRTL(TRUE);
|
104
|
}
|
105
|
|
106
|
$pdf = theme('print_pdf_tcpdf_header', array(
|
107
|
'pdf' => $pdf,
|
108
|
'html' => $html,
|
109
|
'font' => $font,
|
110
|
));
|
111
|
$pdf = theme('print_pdf_tcpdf_footer', array(
|
112
|
'pdf' => $pdf,
|
113
|
'html' => $html,
|
114
|
'font' => $font,
|
115
|
));
|
116
|
$pdf = theme('print_pdf_tcpdf_page', array('pdf' => $pdf));
|
117
|
|
118
|
// Enable third-party module to alter the pdf object, via
|
119
|
// hook_print_pdf_tcpdf_alter().
|
120
|
drupal_alter('print_pdf_tcpdf', $pdf, $html, $meta);
|
121
|
|
122
|
// Add a page.
|
123
|
$pdf->AddPage();
|
124
|
|
125
|
$pdf = theme('print_pdf_tcpdf_content', array(
|
126
|
'pdf' => $pdf,
|
127
|
'html' => $html,
|
128
|
'font' => $font,
|
129
|
));
|
130
|
|
131
|
// Reset pointer to the last page.
|
132
|
$pdf->lastPage();
|
133
|
|
134
|
// Try to recover from any warning/error.
|
135
|
ob_clean();
|
136
|
|
137
|
return $pdf = $pdf->Output('', 'S');
|
138
|
}
|
139
|
|
140
|
/**
|
141
|
* Format the TCPDF header.
|
142
|
*
|
143
|
* @param array $vars
|
144
|
* An associative array containing:
|
145
|
* - $pdf: current TCPDF object
|
146
|
* - $html: contents of the body of the HTML from the original node
|
147
|
* - $font: array with the font definition (font name, styles and size)
|
148
|
*
|
149
|
* @return object
|
150
|
* modified PDF object
|
151
|
*
|
152
|
* @ingroup themeable
|
153
|
* @ingroup print_themeable
|
154
|
*/
|
155
|
function theme_print_pdf_tcpdf_header($vars) {
|
156
|
global $base_url;
|
157
|
|
158
|
$pdf = $vars['pdf'];
|
159
|
preg_match('!<div class="print-logo">(.*?)</div>!si', $vars['html'], $tpl_logo);
|
160
|
preg_match('!<title>(.*?)</title>!si', $vars['html'], $tpl_title);
|
161
|
preg_match('!<div class="print-site_name">(.*?)</div>!si', $vars['html'], $tpl_site_name);
|
162
|
|
163
|
$ratio = 0;
|
164
|
$logo = '';
|
165
|
if (isset($tpl_logo[1]) && preg_match('!src\s*=\s*(?:"(.*?)"|\'(.*?)\'|([^\s]*))!i', $tpl_logo[1], $logo_url)) {
|
166
|
$logo = $logo_url[1];
|
167
|
|
168
|
// Make logo relative again.
|
169
|
$logo = preg_replace("!^$base_url(.*)!sm", DRUPAL_ROOT . '$1', $logo);
|
170
|
|
171
|
if (!empty($logo)) {
|
172
|
$size = getimagesize($logo);
|
173
|
$ratio = $size ? ($size[0] / $size[1]) : 0;
|
174
|
}
|
175
|
}
|
176
|
|
177
|
// Set header font.
|
178
|
$pdf->setHeaderFont($vars['font']);
|
179
|
// Set header margin.
|
180
|
$pdf->setHeaderMargin(5);
|
181
|
// Set header data.
|
182
|
$pdf->setHeaderData($logo, 10 * $ratio, html_entity_decode($tpl_title[1], ENT_QUOTES, 'UTF-8'), html_entity_decode(strip_tags($tpl_site_name[1]), ENT_QUOTES, 'UTF-8'));
|
183
|
|
184
|
return $pdf;
|
185
|
}
|
186
|
|
187
|
/**
|
188
|
* Format the TCPDF page settings (margins, etc).
|
189
|
*
|
190
|
* @param array $vars
|
191
|
* An associative array containing:
|
192
|
* - $pdf: current TCPDF object.
|
193
|
*
|
194
|
* @return object
|
195
|
* modified PDF object
|
196
|
*
|
197
|
* @ingroup themeable
|
198
|
* @ingroup print_themeable
|
199
|
*/
|
200
|
function theme_print_pdf_tcpdf_page($vars) {
|
201
|
$pdf = $vars['pdf'];
|
202
|
// Set margins.
|
203
|
$pdf->SetMargins(15, 20, 15);
|
204
|
// Set auto page breaks.
|
205
|
$pdf->SetAutoPageBreak(TRUE, 15);
|
206
|
// Set image scale factor.
|
207
|
$pdf->setImageScale(1);
|
208
|
// Set image compression quality.
|
209
|
$pdf->setJPEGQuality(100);
|
210
|
|
211
|
return $pdf;
|
212
|
}
|
213
|
|
214
|
/**
|
215
|
* Format the TCPDF page content.
|
216
|
*
|
217
|
* @param array $vars
|
218
|
* An associative array containing:
|
219
|
* - $pdf: current TCPDF object
|
220
|
* - $html: contents of the body of the HTML from the original node
|
221
|
* - $font: array with the font definition (font name, styles and size)
|
222
|
*
|
223
|
* @return object
|
224
|
* modified PDF object
|
225
|
*
|
226
|
* @ingroup themeable
|
227
|
* @ingroup print_themeable
|
228
|
*/
|
229
|
function theme_print_pdf_tcpdf_content($vars) {
|
230
|
$pdf = $vars['pdf'];
|
231
|
// Set content font.
|
232
|
$pdf->setFont($vars['font'][0], $vars['font'][1], $vars['font'][2]);
|
233
|
|
234
|
// Remove the logo, published, breadcrumb and footer from the main content.
|
235
|
preg_match('!<body.*?>(.*)</body>!sim', $vars['html'], $matches);
|
236
|
$pattern = '!(?:<div class="print-(?:logo|site_name|breadcrumb|footer)">.*?</div>|<hr class="print-hr" />)!si';
|
237
|
$matches[1] = preg_replace($pattern, '', $matches[1]);
|
238
|
|
239
|
// Make CCK fields look better.
|
240
|
$matches[1] = preg_replace('!(<div class="field.*?>)\s*!sm', '$1', $matches[1]);
|
241
|
$matches[1] = preg_replace('!(<div class="field.*?>.*?</div>)\s*!sm', '$1', $matches[1]);
|
242
|
$matches[1] = preg_replace('!<div( class="field-label.*?>.*?)</div>!sm', '<strong$1</strong>', $matches[1]);
|
243
|
|
244
|
// Since TCPDF's writeHTML is so bad with <p>, try to make it look nice.
|
245
|
$matches[1] = preg_replace('!<(?:p(|\s+.*?)/?|/p)>!i', '<br$1 />', $matches[1]);
|
246
|
$matches[1] = str_replace(array('<div', 'div>'), array('<span', 'span><br />'), $matches[1]);
|
247
|
do {
|
248
|
$prev = $matches[1];
|
249
|
$matches[1] = preg_replace('!(</span>)<br />(\s*?</span><br />)!s', '$1$2', $matches[1]);
|
250
|
} while ($prev != $matches[1]);
|
251
|
|
252
|
@$pdf->writeHTML($matches[1]);
|
253
|
|
254
|
return $pdf;
|
255
|
}
|
256
|
|
257
|
/**
|
258
|
* Format the TCPDF footer contents.
|
259
|
*
|
260
|
* @param array $vars
|
261
|
* An associative array containing:
|
262
|
* - $pdf: current TCPDF object
|
263
|
* - $html: contents of the body of the HTML from the original node
|
264
|
* - $font: array with the font definition (font name, styles and size)
|
265
|
*
|
266
|
* @return object
|
267
|
* modified PDF object
|
268
|
*
|
269
|
* @ingroup themeable
|
270
|
* @ingroup print_themeable
|
271
|
*/
|
272
|
function theme_print_pdf_tcpdf_footer($vars) {
|
273
|
$pdf = $vars['pdf'];
|
274
|
preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer);
|
275
|
|
276
|
if (isset($tpl_footer[1])) {
|
277
|
$footer = trim(preg_replace('!</?div[^>]*?>!i', '', $tpl_footer[1]));
|
278
|
|
279
|
// Set footer font.
|
280
|
$vars['font'][2] *= 0.8;
|
281
|
$pdf->setFooterFont($vars['font']);
|
282
|
// Set footer margin.
|
283
|
$pdf->SetFooterMargin(10);
|
284
|
// Set footer data.
|
285
|
$pdf->setFooterContent($footer);
|
286
|
}
|
287
|
|
288
|
return $pdf;
|
289
|
}
|
290
|
|
291
|
/**
|
292
|
* Format the TCPDF footer layout.
|
293
|
*
|
294
|
* @param array $vars
|
295
|
* An associative array containing:
|
296
|
* - $pdf: current TCPDF object.
|
297
|
*
|
298
|
* @return object
|
299
|
* modified PDF object
|
300
|
*
|
301
|
* @ingroup themeable
|
302
|
* @ingroup print_themeable
|
303
|
*/
|
304
|
function theme_print_pdf_tcpdf_footer2($vars) {
|
305
|
$pdf = $vars['pdf'];
|
306
|
// Position at 1.5 cm from bottom.
|
307
|
$pdf->writeHTMLCell(0, 15, 15, $pdf->getPageHeight() - 15, $pdf->footer);
|
308
|
|
309
|
$ormargins = $pdf->getOriginalMargins();
|
310
|
$pagenumtxt = t('Page !n of !total', array('!n' => $pdf->PageNo(), '!total' => $pdf->getAliasNbPages()));
|
311
|
// Print page number.
|
312
|
if ($pdf->getRTL()) {
|
313
|
$pdf->SetX($ormargins['right']);
|
314
|
$pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'L');
|
315
|
}
|
316
|
else {
|
317
|
$pdf->SetX($ormargins['left']);
|
318
|
$pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'R');
|
319
|
}
|
320
|
|
321
|
return $pdf;
|
322
|
}
|