1<?php 2// $Header: /cvsroot/html2ps/output.fastps.class.php,v 1.18 2007/05/17 13:55:13 Konstantin Exp $ 3 4define('FASTPS_STATUS_DOCUMENT_INITIALIZED',0); 5define('FASTPS_STATUS_OUTPUT_STARTED',1); 6define('FASTPS_STATUS_OUTPUT_TERMINATED',2); 7 8class OutputDriverFastPS extends OutputDriverGenericPS { 9 var $found_fonts; 10 var $used_encodings; 11 var $font_factory; 12 var $status; 13 14 var $overline; 15 var $underline; 16 var $linethrough; 17 18 function OutputDriverFastPS(&$image_encoder) { 19 $this->OutputDriverGenericPS($image_encoder); 20 } 21 22 function add_link($x, $y, $w, $h, $target) { 23 $this->write(sprintf("[ /Rect [ %.2f %.2f %.2f %.2f ] /Action << /Subtype /URI /URI (%s) >> /Border [0 0 0] /Subtype /Link /ANN pdfmark\n", 24 $x, $y, $x+$w, $y-$h, $this->_string($target))); 25 } 26 27 function add_local_link($left, $top, $width, $height, $anchor) { 28 $this->write(sprintf("[ /Rect [ %.2f %.2f %.2f %.2f ] /Page %d /View [ /XYZ null %.2f null ] /Border [0 0 0] /Subtype /Link /ANN pdfmark\n", 29 $left, $top, $left + $width, $top - $height, $anchor->page, $anchor->y)); 30 } 31 32 function circle($x, $y, $r) { 33 $this->moveto($x, $y); 34 $this->write(sprintf("%.2f %.2f %.2f 0 360 arc\n", $x, $y, $r)); 35 } 36 37 function clip() { 38 $this->write("clip newpath\n"); 39 } 40 41 function close() { 42 $this->_terminate_output(); 43 fclose($this->data); 44 } 45 46 function closepath() { 47 $this->write("closepath\n"); 48 } 49 50 function dash($x, $y) { 51 $this->write(sprintf("[%.2f %.2f] 0 setdash\n", $x, $y)); 52 } 53 54 function decoration($underline, $overline, $linethrough) { 55 $this->underline = $underline; 56 $this->overline = $overline; 57 $this->linethrough = $linethrough; 58 } 59 60 function fill() { 61 $this->write("fill\n"); 62 } 63 64 function _findfont($name, $encoding) { 65 $font =& $this->font_factory->get_type1($name, $encoding); 66 if (is_null($font)) { 67 $this->error_message .= $this->font_factory->error_message(); 68 $dummy = null; 69 return $dummy; 70 }; 71 72 if (!isset($this->used_encodings[$encoding])) { 73 $this->used_encodings[$encoding] = true; 74 75 $manager = ManagerEncoding::get(); 76 $this->_write_document_prolog($manager->get_ps_encoding_vector($encoding)); 77 $this->_write_document_prolog("\n"); 78 }; 79 80 $fontname = $font->name(); 81 if (!isset($this->found_fonts[$fontname])) { 82 $this->found_fonts[$fontname] = true; 83 84 $this->_write_document_prolog("/$fontname /$name $encoding findfont-enc def\n"); 85 }; 86 87 return $font; 88 } 89 90 // @return 'null' in case of error or ascender fraction of font-size 91 // 92 function font_ascender($name, $encoding) { 93 $font = $this->_findfont($name, $encoding); 94 if (is_null($font)) { return null; }; 95 96 return $font->ascender()/1000; 97 } 98 99 // @return 'null' in case of error or ascender fraction of font-size 100 // 101 function font_descender($name, $encoding) { 102 $font = $this->_findfont($name, $encoding); 103 if (is_null($font)) { return null; }; 104 105 return -$font->descender()/1000; 106 } 107 108 function get_bottom() { 109 return $this->bottom + $this->offset; 110 } 111 112 function &get_font_resolver() { 113 global $g_font_resolver; 114 return $g_font_resolver; 115 } 116 117 function image($image, $x, $y, $scale) { 118 $image_encoder = $this->get_image_encoder(); 119 $id = $image_encoder->auto($this, $image, $size_x, $size_y, $tcolor, $image, $mask); 120 $init = "image-".$id."-init"; 121 122 $this->moveto($x, $y); 123 $this->write(sprintf("%.2f %.2f %s %s {%s} %d %d image-create image-show\n", 124 $size_x * $scale, 125 $size_y * $scale, 126 ($mask !== "" ? $mask : "/null"), 127 $image, 128 $init, 129 $size_y, 130 $size_x)); 131 } 132 133 function image_scaled($image, $x, $y, $scale_x, $scale_y) { 134 $image_encoder = $this->get_image_encoder(); 135 $id = $image_encoder->auto($this, $image, $size_x, $size_y, $tcolor, $image, $mask); 136 $init = "image-".$id."-init"; 137 138 $this->moveto($x, $y); 139 $this->write(sprintf("%.2f %.2f %s %s {%s} %d %d image-create image-show\n", 140 $size_x * $scale_x , 141 $size_y * $scale_y, 142 ($mask !== "" ? $mask : "/null"), 143 $image, 144 $init, 145 $size_y, 146 $size_x)); 147 } 148 149 function image_ry($image, $x, $y, $height, $bottom, $ox, $oy, $scale) { 150 $image_encoder = $this->get_image_encoder(); 151 $id = $image_encoder->auto($this, $image, $size_x, $size_y, $tcolor, $image, $mask); 152 $init = "image-".$id."-init"; 153 154 $this->write(sprintf("%.2f %.2f %.2f %.2f %.2f %.2f %.2f %s %s {%s} %d %d image-create image-show-repeat-y\n", 155 $scale, $oy, $ox, $bottom, $height, $y, $x, 156 ($mask !== "" ? $mask : "/null"), 157 $image, 158 $init, 159 $size_y, 160 $size_x)); 161 } 162 163 function image_rx($image, $x, $y, $width, $right, $ox, $oy, $scale) { 164 $image_encoder = $this->get_image_encoder(); 165 $id = $image_encoder->auto($this, $image, $size_x, $size_y, $tcolor, $image, $mask); 166 $init = "image-".$id."-init"; 167 168 $this->write(sprintf("%.2f %.2f %.2f %.2f %.2f %.2f %.2f %s %s {%s} %d %d image-create image-show-repeat-x\n", 169 $scale, $oy, $ox, $right, $width, $y, $x, 170 ($mask !== "" ? $mask : "/null"), 171 $image, 172 $init, 173 $size_y, 174 $size_x)); 175 } 176 177 function image_rx_ry($image, $x, $y, $width, $height, $right, $bottom, $ox, $oy, $scale) { 178 $image_encoder = $this->get_image_encoder(); 179 $id = $image_encoder->auto($this, $image, $size_x, $size_y, $tcolor, $image, $mask); 180 $init = "image-".$id."-init"; 181 182 $this->write(sprintf("%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %s %s {%s} %d %d image-create image-show-repeat-xy\n", 183 $scale, $oy, $ox, $bottom, $right, $height, $width, $y, $x, 184 ($mask !== "" ? $mask : "/null"), 185 $image, 186 $init, 187 $size_y, 188 $size_x)); 189 } 190 191 function lineto($x, $y) { 192 $data = sprintf("%.2f %.2f lineto\n", $x, $y); 193 $this->write($data); 194 } 195 196 function moveto($x, $y) { 197 $data = sprintf("%.2f %.2f moveto\n", $x, $y); 198 $this->write($data); 199 } 200 201 function next_page($height) { 202 if ($this->current_page > 0) { 203 $this->write("showpage\n"); 204 }; 205 206 $this->offset -= $height - $this->offset_delta; 207 208 // Reset the "correction" offset to it normal value 209 // Note: "correction" offset is an offset value required to avoid page breaking 210 // in the middle of text boxes 211 $this->offset_delta = 0; 212 213 $this->write(sprintf("%%%%Page: %d %d\n", $this->current_page + 1, $this->current_page + 1)); 214 $this->write("%%BeginPageSetup\n"); 215 $this->write(sprintf("initpage\n")); 216 $this->write(sprintf("0 %.2f translate\n", -$this->offset)); 217 $this->write("0 0 0 setrgbcolor\n"); 218 $this->write("%%EndPageSetup\n"); 219 220 parent::next_page($height); 221 } 222 223 function reset(&$media) { 224 OutputDriverGenericPS::reset($media); 225 226 $this->media =& $media; 227 $this->data = fopen($this->get_filename(), "wb"); 228 229 // List of fonts names which already had generated findfond PS code 230 $this->found_fonts = array(); 231 232 $this->used_encodings = array(); 233 234 $this->overline = false; 235 $this->underline = false; 236 $this->linethrough = false; 237 238 // A font class factory 239 $this->font_factory =& new FontFactory; 240 241 $this->_document_body = ''; 242 $this->_document_prolog = ''; 243 244 $this->status = FASTPS_STATUS_DOCUMENT_INITIALIZED; 245 } 246 247 function restore() { 248 $this->write("grestore\n"); 249 } 250 251 function save() { 252 $this->write("gsave\n"); 253 } 254 255 // @return true normally or null in case of error 256 // 257 function setfont($name, $encoding, $size) { 258 $this->fontsize = $size; 259 $this->currentfont = $this->_findfont($name, $encoding); 260 261 if (is_null($this->currentfont)) { return null; }; 262 263 $this->write(sprintf("%s %.2f scalefont setfont\n", $this->currentfont->name(), $size)); 264 265 return true; 266 } 267 268 function setlinewidth($x) { 269 $data = sprintf("%.2f setlinewidth\n", $x); 270 $this->write($data); 271 } 272 273 function setrgbcolor($r, $g, $b) { 274 $data = sprintf("%.2f %.2f %.2f setrgbcolor\n", $r, $g, $b); 275 $this->write($data); 276 } 277 278 function show_xy($text, $x, $y) { 279 if (trim($text) !== '') { 280 $this->moveto($x, $y); 281 $this->write("(".$this->_string($text).") show\n"); 282 }; 283 284 $width = Font::points($this->fontsize, $this->currentfont->stringwidth($text)); 285 if ($this->overline) { $this->_show_overline($x, $y, $width, $this->fontsize); }; 286 if ($this->underline) { $this->_show_underline($x, $y, $width, $this->fontsize); }; 287 if ($this->linethrough) { $this->_show_linethrough($x, $y, $width, $this->fontsize); }; 288 } 289 290 function stringwidth($string, $name, $encoding, $size) { 291 $font =& $this->font_factory->get_type1($name, $encoding); 292 293 if (is_null($font)) { 294 $this->error_message .= $this->font_factory->error_message(); 295 $dummy = null; 296 return $dummy; 297 }; 298 299 return Font::points($size, $font->stringwidth($string)); 300 } 301 302 function stroke() { 303 $this->write("stroke\n"); 304 } 305 306 function write($string) { 307 if ($this->status == FASTPS_STATUS_DOCUMENT_INITIALIZED) { 308 $this->_start_output(); 309 }; 310 311 $this->_document_body .= $string; 312 } 313 314 function _write_document_prolog($string) { 315 $this->_document_prolog .= $string; 316 } 317 318 function _show_line($x, $y, $width, $height, $up, $ut) { 319 $this->setlinewidth($ut); 320 $this->moveto($x, $y + $up); 321 $this->lineto($x+$width, $y + $up); 322 $this->stroke(); 323 } 324 325 function _show_underline($x, $y, $width, $height) { 326 $up = Font::points($this->fontsize, $this->currentfont->underline_position()); 327 $ut = Font::points($this->fontsize, $this->currentfont->underline_thickness()); 328 329 $this->_show_line($x, $y, $width, $height, $up, $ut); 330 } 331 332 function _show_overline($x, $y, $width, $height) { 333 $up = Font::points($this->fontsize, $this->currentfont->overline_position()); 334 $ut = Font::points($this->fontsize, $this->currentfont->underline_thickness()); 335 336 $this->_show_line($x, $y, $width, $height, $up, $ut); 337 } 338 339 function _show_linethrough($x, $y, $width, $height) { 340 $up = Font::points($this->fontsize, $this->currentfont->linethrough_position()); 341 $ut = Font::points($this->fontsize, $this->currentfont->underline_thickness()); 342 343 $this->_show_line($x, $y, $width, $height, $up, $ut); 344 } 345 346 function _start_output() { 347 $this->status = FASTPS_STATUS_OUTPUT_STARTED; 348 } 349 350 function _terminate_output() { 351 /** 352 * Prepare the PS file header 353 * Note that %PS-Adobe-3.0 refers to DSC version, NOT language level 354 */ 355 $header = file_get_contents(HTML2PS_DIR.'postscript/fastps.header.ps'); 356 357 global $g_config; 358 $header = preg_replace("/##PS2PDF##/", 359 ($g_config['ps2pdf'] && $g_config['transparency_workaround']) ? "/ps2pdf-transparency-hack true def" : "/ps2pdf-transparency-hack false def",$header); 360 $header = preg_replace("/##TRANSPARENCY##/",($g_config['transparency_workaround']) ? "/no-transparency-output true def" : "/no-transparency-output false def",$header); 361 $header = preg_replace("/##PAGES##/", $this->expected_pages, $header); 362 363 $header = preg_replace("/##BBOX##/", $this->media->to_bbox(), $header); 364 $header = preg_replace("/##MEDIA##/", $this->media->to_ps(), $header); 365 366 $header = preg_replace("/##PROLOG##/", $this->_document_prolog, $header); 367 368 fwrite($this->data, $header); 369 fwrite($this->data, "\n"); 370 fwrite($this->data, $this->_document_body); 371 372 $footer = file_get_contents(HTML2PS_DIR.'postscript/fastps.footer.ps'); 373 fwrite($this->data, $footer); 374 } 375 376 function _show_watermark() { 377 } 378 379 /** 380 * Protected output-specific methods 381 */ 382 383 /** 384 * Escapes special Postscript symbols '(',')' and '%' inside a text string 385 */ 386 function _string($str) { 387 $str = str_replace("\\", "\\\\", $str); 388 $str = str_replace(array("(",")","%"), array("\\(","\\)","\\%"), $str); 389 390 // Replace characters having 8-bit set with their octal representation 391 for ($i=0; $i<strlen($str); $i++) { 392 if (ord($str{$i}) > 127) { 393 $str = substr_replace($str, sprintf("\\%o", ord($str{$i})), $i, 1); 394 $i += 3; 395 }; 396 }; 397 398 return $str; 399 } 400} 401 402?>