1<?php
2// $Header: /cvsroot/html2ps/output.pdflib.class.php,v 1.18 2007/05/17 13:55:13 Konstantin Exp $
3
4define('PDFLIB_STATUS_INITIALIZED', 0);
5define('PDFLIB_STATUS_DOCUMENT_STARTED', 1);
6define('PDFLIB_STATUS_PAGE_STARTED', 2);
7
8class OutputDriverPdflib extends OutputDriverGenericPDF {
9  var $pdf;
10
11  /**
12   * @var ? Contains the PDFLIB handle of currently selected PDF font
13   * @access private
14   */
15  var $_currentfont;
16  var $_forms;
17  var $_field_names;
18
19  var $_radiogroups;
20  var $_watermark;
21
22  var $_status;
23
24  // Converts common encoding names to their PDFLIB equivalents
25  // (for example, PDFLIB does not understand iso-8859-1 encoding name,
26  // but have its equivalent names winansi..)
27  //
28   function encoding($encoding) {
29    $encoding = trim(strtolower($encoding));
30
31    $translations = array('iso-8859-1'   => 'winansi',
32                          'iso-8859-2'   => 'iso8859-2',
33                          'iso-8859-3'   => 'iso8859-3',
34                          'iso-8859-4'   => 'iso8859-4',
35                          'iso-8859-5'   => 'iso8859-5',
36                          'iso-8859-6'   => 'iso8859-6',
37                          'iso-8859-7'   => 'iso8859-7',
38                          'iso-8859-8'   => 'iso8859-8',
39                          'iso-8859-9'   => 'iso8859-9',
40                          'iso-8859-10'  => 'iso8859-10',
41                          'iso-8859-13'  => 'iso8859-13',
42                          'iso-8859-14'  => 'iso8859-14',
43                          'iso-8859-15'  => 'iso8859-15',
44                          'iso-8859-16'  => 'iso8859-16',
45                          'windows-1250' => 'cp1250',
46                          'windows-1251' => 'cp1251',
47                          'windows-1252' => 'cp1252',
48                          'symbol'       => 'symbol');
49
50    if (isset($translations[$encoding])) { return $translations[$encoding]; };
51    return $encoding;
52  }
53
54  function add_link($left, $top, $width, $height, $url) {
55    pdf_add_weblink($this->pdf, $left, $top-$height, $left+$width, $top, $url);
56  }
57
58  function add_local_link($left, $top, $width, $height, $anchor) {
59    pdf_add_locallink($this->pdf,
60                      $left,
61                      $top-$height - $this->offset ,
62                      $left+$width,
63                      $top - $this->offset,
64                      $anchor->page,
65                      "fitwidth");
66  }
67
68  function circle($x, $y, $r) {
69    pdf_circle($this->pdf, $x, $y, $r);
70  }
71
72  function clip() {
73    pdf_clip($this->pdf);
74  }
75
76  function close() {
77    pdf_end_page($this->pdf);
78    pdf_close($this->pdf);
79    pdf_delete($this->pdf);
80  }
81
82  function closepath() {
83    pdf_closepath($this->pdf);
84  }
85
86  function dash($x, $y) {
87    pdf_setdash($this->pdf, $x, $y);
88  }
89
90  function decoration($underline, $overline, $strikeout) {
91    // underline
92    pdf_set_parameter($this->pdf, "underline", $underline ? "true" : "false");
93    // overline
94    pdf_set_parameter($this->pdf, "overline",  $overline  ? "true" : "false");
95    // line through
96    pdf_set_parameter($this->pdf, "strikeout", $strikeout ? "true" : "false");
97  }
98
99  function fill() {
100    pdf_fill($this->pdf);
101  }
102
103  function findfont($name, $encoding) {
104    // PDFLIB is limited by 'builtin' encoding for "Symbol" font
105    if ($name == 'Symbol') {
106      $encoding = 'builtin';
107    };
108
109    global $g_font_resolver_pdf;
110    $embed = $g_font_resolver_pdf->embed[$name];
111    return pdf_findfont($this->pdf, $name, $this->encoding($encoding), $embed);
112  }
113
114  function font_ascender($name, $encoding) {
115    return pdf_get_value($this->pdf, "ascender", $this->findfont($name, $encoding));
116  }
117
118  function font_descender($name, $encoding) {
119    return -pdf_get_value($this->pdf, "descender", $this->findfont($name, $encoding));
120  }
121
122  function get_bottom() {
123    return $this->bottom + $this->offset;
124  }
125
126  function image($image, $x, $y, $scale) {
127    $tmpname = tempnam(WRITER_TEMPDIR,WRITER_FILE_PREFIX);
128    imagepng($image->get_handle(), $tmpname);
129    $pim = pdf_open_image_file($this->pdf, "png", $tmpname, "", 0);
130    pdf_place_image($this->pdf, $pim, $x, $y, $scale);
131    pdf_close_image($this->pdf, $pim);
132    unlink($tmpname);
133  }
134
135  function image_scaled($image, $x, $y, $scale_x, $scale_y) {
136    $tmpname = tempnam(WRITER_TEMPDIR,WRITER_FILE_PREFIX);
137    imagepng($image->get_handle(), $tmpname);
138
139    $pim = pdf_open_image_file($this->pdf, "png", $tmpname, "", 0);
140
141    $this->save();
142    pdf_translate($this->pdf, $x, $y);
143    pdf_scale($this->pdf, $scale_x, $scale_y);
144    pdf_place_image($this->pdf, $pim, 0, 0, 1);
145    $this->restore();
146
147    pdf_close_image($this->pdf, $pim);
148    unlink($tmpname);
149  }
150
151  function image_ry($image, $x, $y, $height, $bottom, $ox, $oy, $scale) {
152    $tmpname = tempnam(WRITER_TEMPDIR,WRITER_FILE_PREFIX);
153    imagepng($image->get_handle(), $tmpname);
154    $pim = pdf_open_image_file($this->pdf, "png", $tmpname, "", 0);
155
156    // Fill part to the bottom
157    $cy = $y;
158    while ($cy+$height > $bottom) {
159      pdf_place_image($this->pdf, $pim, $x, $cy, $scale);
160      $cy -= $height;
161    };
162
163    // Fill part to the top
164    $cy = $y;
165    while ($cy-$height < $y + $oy) {
166      pdf_place_image($this->pdf, $pim, $x, $cy, $scale);
167      $cy += $height;
168    };
169
170    pdf_close_image($this->pdf, $pim);
171    unlink($tmpname);
172  }
173
174  function image_rx($image, $x, $y, $width, $right, $ox, $oy, $scale) {
175    $tmpname = tempnam(WRITER_TEMPDIR,WRITER_FILE_PREFIX);
176    imagepng($image->get_handle(), $tmpname);
177    $pim = pdf_open_image_file($this->pdf, "png", $tmpname, "", 0);
178
179    // Fill part to the right
180    $cx = $x;
181    while ($cx < $right) {
182      pdf_place_image($this->pdf, $pim, $cx, $y, $scale);
183      $cx += $width;
184    };
185
186    // Fill part to the left
187    $cx = $x;
188    while ($cx+$width >= $x - $ox) {
189      pdf_place_image($this->pdf, $pim, $cx-$width, $y, $scale);
190      $cx -= $width;
191    };
192
193    pdf_close_image($this->pdf, $pim);
194    unlink($tmpname);
195  }
196
197  function image_rx_ry($image, $x, $y, $width, $height, $right, $bottom, $ox, $oy, $scale) {
198    $tmpname = tempnam(WRITER_TEMPDIR,WRITER_FILE_PREFIX);
199    imagepng($image->get_handle(), $tmpname);
200    $pim = pdf_open_image_file($this->pdf, "png", $tmpname, "", 0);
201
202    // Fill bottom-right quadrant
203    $cy = $y;
204    while ($cy+$height > $bottom) {
205      $cx = $x;
206      while ($cx < $right) {
207        pdf_place_image($this->pdf, $pim, $cx, $cy, $scale);
208        $cx += $width;
209      };
210      $cy -= $height;
211    }
212
213    // Fill bottom-left quadrant
214    $cy = $y;
215    while ($cy+$height > $bottom) {
216      $cx = $x;
217      while ($cx+$width > $x - $ox) {
218        pdf_place_image($this->pdf, $pim, $cx, $cy, $scale);
219        $cx -= $width;
220      };
221      $cy -= $height;
222    }
223
224    // Fill top-right quadrant
225    $cy = $y;
226    while ($cy < $y + $oy) {
227      $cx = $x;
228      while ($cx < $right) {
229        pdf_place_image($this->pdf, $pim, $cx, $cy, $scale);
230        $cx += $width;
231      };
232      $cy += $height;
233    }
234
235    // Fill top-left quadrant
236    $cy = $y;
237    while ($cy < $y + $oy) {
238      $cx = $x;
239      while ($cx+$width > $x - $ox) {
240        pdf_place_image($this->pdf, $pim, $cx, $cy, $scale);
241        $cx -= $width;
242      };
243      $cy += $height;
244    }
245
246    pdf_close_image($this->pdf, $pim);
247    unlink($tmpname);
248  }
249
250  function lineto($x, $y) {
251    pdf_lineto($this->pdf, $x, $y);
252  }
253
254  function moveto($x, $y) {
255    pdf_moveto($this->pdf, $x, $y);
256  }
257
258  // OutputDriver interface functions
259  function next_page($height) {
260    if ($this->_status == PDFLIB_STATUS_PAGE_STARTED) {
261      pdf_end_page($this->pdf);
262    };
263    pdf_begin_page($this->pdf, mm2pt($this->media->width()), mm2pt($this->media->height()));
264
265    // Calculate coordinate of the next page bottom edge
266    $this->offset -= $height - $this->offset_delta;
267
268    // Reset the "correction" offset to it normal value
269    // Note: "correction" offset is an offset value required to avoid page breaking
270    // in the middle of text boxes
271    $this->offset_delta = 0;
272
273    pdf_translate($this->pdf, 0, -$this->offset);
274
275    parent::next_page($height);
276
277    $this->_status = PDFLIB_STATUS_PAGE_STARTED;
278  }
279
280  function OutputDriverPdflib($version) {
281    $this->OutputDriverGenericPDF();
282    $this->set_pdf_version($version);
283
284    $this->_currentfont = null;
285    $this->_radiogroups = array();
286    $this->_field_names = array();
287
288    $this->_status = PDFLIB_STATUS_INITIALIZED;
289  }
290
291  function prepare() {
292    parent::prepare();
293
294    // Generate custom encoding vector mappings
295    $manager_encoding = ManagerEncoding::get();
296    for ($i = 1, $size = $manager_encoding->get_custom_vector_index(); $i <= $size; $i++) {
297      $encoding_name = $manager_encoding->get_custom_encoding_name($i);
298      $filename = $this->generate_cpg($encoding_name,
299                                      true);
300      pdf_set_parameter($this->pdf,
301                        'Encoding',
302                        sprintf('%s=%s',
303                                $encoding_name,
304                                $filename));
305    };
306  }
307
308  function reset(&$media) {
309    OutputDriverGenericPDF::reset($media);
310
311    // Check if PDFLIB is available
312    if (!extension_loaded('pdf')) {
313
314      // Try to use "dl" to dynamically load PDFLIB
315      $result = dl(PDFLIB_DL_PATH);
316
317      if (!$result) {
318        readfile(HTML2PS_DIR.'templates/missing_pdflib.html');
319        error_log("No PDFLIB extension found");
320        die("HTML2PS Error");
321      }
322    }
323
324    $this->pdf = pdf_new();
325
326    // Set PDF compatibility level
327    pdf_set_parameter($this->pdf, "compatibility", $this->get_pdf_version());
328
329    /**
330     * Use PDF license key, if present
331     *
332     * PDFLIB_LICENSE constant is defined in 'config.inc.php' file in "PDFLIB-specific" section.
333     */
334    if (defined("PDFLIB_LICENSE")) {
335      pdf_set_parameter($this->pdf, "license", PDFLIB_LICENSE);
336    };
337
338    pdf_open_file($this->pdf, $this->get_filename());
339
340    // @TODO: compression level, debug
341    pdf_set_value($this->pdf, "compress", 0);
342
343    // Set path to the PDFLIB UPR file containig information about fonts and encodings
344    if (defined("PDFLIB_UPR_PATH")) {
345      pdf_set_parameter($this->pdf, "resourcefile", PDFLIB_UPR_PATH);
346    };
347
348    // Setup encodings not bundled with PDFLIB
349    $filename = $this->generate_cpg('koi8-r');
350    pdf_set_parameter($this->pdf, 'Encoding', sprintf('koi8-r=%s', $filename));
351
352    // Setup font outlines
353    global $g_font_resolver_pdf;
354    $g_font_resolver_pdf->setup_ttf_mappings($this->pdf);
355
356    $pdf = $this->pdf;
357    pdf_set_info($pdf, "Creator", "html2ps (PHP version)");
358
359    // No borders around links in the generated PDF
360    pdf_set_border_style($this->pdf, "solid", 0);
361
362    $this->_status = PDFLIB_STATUS_DOCUMENT_STARTED;
363  }
364
365  function rect($x, $y, $w, $h) {
366    pdf_rect($this->pdf, $x, $y, $w, $h);
367  }
368
369  function restore() {
370    pdf_restore($this->pdf);
371  }
372
373  function save() {
374    pdf_save($this->pdf);
375  }
376
377  function setfont($name, $encoding, $size) {
378    $this->_currentfont = $this->findfont($name, $encoding);
379
380    pdf_setfont($this->pdf, $this->_currentfont, $size);
381
382    return true;
383  }
384
385//   function setfontcore($name, $size) {
386//     $this->_currentfont = pdf_findfont($this->pdf, $name, 'host', 1 /* embed */);
387
388//     pdf_setfont($this->pdf, $this->_currentfont, $size);
389
390//     return true;
391//   }
392
393  function setlinewidth($x) {
394    pdf_setlinewidth($this->pdf, $x);
395  }
396
397  // PDFLIB wrapper functions
398  function setrgbcolor($r, $g, $b)  {
399    pdf_setcolor($this->pdf, "both", "rgb", $r, $g, $b, 0);
400  }
401
402  function show_xy($text, $x, $y) {
403    pdf_show_xy($this->pdf, $text, $x, $y);
404  }
405
406  function stroke() {
407    pdf_stroke($this->pdf);
408  }
409
410  function stringwidth($string, $name, $encoding, $size) {
411    return pdf_stringwidth($this->pdf, $string, $this->findfont($name, $encoding), $size);
412  }
413
414  /* private routines */
415
416  function _show_watermark($watermark) {
417    $font = $this->findfont('Helvetica', 'iso-8859-1');
418    pdf_setfont($this->pdf, $font, 100);
419
420    $x = $this->left + $this->width / 2;
421    $y = $this->bottom + $this->height / 2 + $this->offset;
422
423    pdf_set_value($this->pdf, "textrendering", 1);
424    pdf_translate($this->pdf, $x, $y);
425    pdf_rotate($this->pdf, 60);
426    pdf_show_xy($this->pdf, $watermark, -pdf_stringwidth($this->pdf, $watermark, $font, 100)/2, -50);
427  }
428
429  function generate_cpg($encoding, $force = false) {
430    if (!$force) {
431      $filename = CACHE_DIR.$encoding.'.cpg';
432    } else {
433      $filename = CACHE_DIR.uniqid('', false).'.cpg';
434    };
435
436    if (file_exists($filename)) {
437      return $filename;
438    };
439
440    $output = fopen($filename, 'w');
441    $manager_encoding =& ManagerEncoding::get();
442    $vector = $manager_encoding->get_encoding_vector($encoding);
443
444    foreach ($vector as $code => $utf) {
445      fwrite($output, sprintf("0x%04X 0x%02X\n", $utf, ord($code)));
446    };
447    fclose($output);
448
449    return $filename;
450  }
451}
452?>