1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8/* This library is LGPL
9 * written by Louis-Philippe Huberdeau
10 *
11 * vim: fdm=marker tabstop=4 shiftwidth=4 noet:
12 *
13 * This file contains the PostScript graphic renderer. (Using PSLib)
14 */
15require_once('lib/graph-engine/core.php');
16
17class PS_GRenderer extends GRenderer // {{{1
18{
19	var $ps;
20	var $styles;
21	var $font;
22
23	var $width;
24	var $height;
25
26	function __construct($format = null, $orientation = 'landscape') // {{{2
27	{
28		// Null size does not create a graphic.
29		$this->styles = [];
30		$this->font = null;
31
32		if (! is_null($format)) {
33			$size = $this->_getFormat($format, $orientation);
34			$this->width = $size[0];
35			$this->height = $size[1];
36
37			$this->ps = ps_new();
38			ps_open_file($this->ps, '');
39			ps_begin_page($this->ps, $this->width, $this->height);
40
41			$this->font = ps_findfont($this->ps, 'Helvetica', '', 0);
42		}
43	}
44
45	function addLink($target, $left, $top, $right, $bottom, $title = null) // {{{2
46	{
47	}
48
49	function drawLine($x1, $y1, $x2, $y2, $style) // {{{2
50	{
51		$this->_convertPosition($x1, $y1);
52		$this->_convertPosition($x2, $y2);
53
54		ps_setcolor(
55			$this->ps,
56			'stroke',
57			$style['line'][0],
58			$style['line'][1],
59			$style['line'][2],
60			$style['line'][3],
61			$style['line'][4]
62		);
63
64		ps_setlinewidth($this->ps, $style['line-width']);
65
66		ps_moveto($this->ps, $x1, $y1);
67		ps_lineto($this->ps, $x2, $y2);
68		ps_stroke($this->ps);
69	}
70
71	function drawRectangle($left, $top, $right, $bottom, $style) // {{{2
72	{
73		$this->_convertPosition($left, $top);
74		$this->_convertPosition($right, $bottom);
75
76		ps_setcolor(
77			$this->ps,
78			'stroke',
79			$style['line'][0],
80			$style['line'][1],
81			$style['line'][2],
82			$style['line'][3],
83			$style['line'][4]
84		);
85
86		if (isset($style['fill'])) {
87			ps_setcolor(
88				$this->ps,
89				'fill',
90				$style['fill'][0],
91				$style['fill'][1],
92				$style['fill'][2],
93				$style['fill'][3],
94				$style['fill'][4]
95			);
96		}
97
98		ps_setlinewidth($this->ps, $style['line-width']);
99
100		ps_rect($this->ps, $left, $top, $right - $left, $bottom - $top);
101
102		if (isset($style['fill'])) {
103			ps_fill_stroke($this->ps);
104		} else {
105			ps_stroke($this->ps);
106		}
107	}
108
109	function drawPie($centerX, $centerY, $radius, $begin, $end, $style) // {{{2
110	{
111		$this->_convertPosition($centerX, $centerY);
112		$radius = $radius * min($this->width, $this->height);
113
114		ps_setcolor(
115			$this->ps,
116			'stroke',
117			$style['line'][0],
118			$style['line'][1],
119			$style['line'][2],
120			$style['line'][3],
121			$style['line'][4]
122		);
123
124		if (isset($style['fill'])) {
125			ps_setcolor(
126				$this->ps,
127				'fill',
128				$style['fill'][0],
129				$style['fill'][1],
130				$style['fill'][2],
131				$style['fill'][3],
132				$style['fill'][4]
133			);
134		}
135
136		ps_setlinewidth($this->ps, $style['line-width']);
137
138		ps_moveto($this->ps, $centerX, $centerY);
139		ps_arc($this->ps, $centerX, $centerY, $radius, $begin, $end);
140		ps_lineto($this->ps, $centerX, $centerY);
141		ps_closepath($this->ps);
142
143		if (isset($style['fill'])) {
144			ps_fill_stroke($this->ps);
145		} else {
146			ps_stroke($this->ps);
147		}
148	}
149
150	function drawText($text, $left, $right, $height, $style) // {{{2
151	{
152		$h = $height; // Creating duplicate (temp)
153		$this->_convertPosition($left, $height);
154		$this->_convertPosition($right, $h);
155
156		ps_setcolor(
157			$this->ps,
158			'fill',
159			$style['fill'][0],
160			$style['fill'][1],
161			$style['fill'][2],
162			$style['fill'][3],
163			$style['fill'][4]
164		);
165
166		ps_setfont($this->ps, $this->font, $style['font']);
167		ps_show_boxed($this->ps, $text, $left, $height - $style['font'], $right - $left, $style['font'], $style['align'], '');
168	}
169
170	function getTextWidth($text, $style) // {{{2
171	{
172		return ps_stringwidth($this->ps, $text, $this->font, $style['font']) / $this->width;
173	}
174
175	function getTextHeight($style) // {{{2
176	{
177		return $style['font'] / $this->height;
178	}
179
180	function getStyle($name) // {{{2
181	{
182		if (isset($this->styles[$name])) {
183			return $this->styles[$name];
184		}
185
186		return $this->styles[$name] = $this->_findStyle($name);
187	}
188
189	function httpOutput($filename) // {{{2
190	{
191		ps_end_page($this->ps);
192		ps_close($this->ps);
193
194		$buf = ps_get_buffer($this->ps);
195		$len = strlen($buf);
196
197		header("Content-type: application/ps");
198		header("Content-Length: $len");
199		header("Content-Disposition: inline; filename=$name");
200		echo $buf;
201
202		ps_delete($this->ps);
203	}
204
205	function writeToStream($stream) // {{{2
206	{
207		ps_end_page($this->ps);
208		ps_close($this->ps);
209
210		$buf = ps_get_buffer($this->ps);
211		fwrite($stream, $buf);
212
213		ps_delete($this->ps);
214	}
215
216	function _convertLength($value, $type) // {{{2
217	{
218		// $type is either 'width' or 'height'
219		// $value is a 0-1 float
220		return floor($value * $this->$type);
221	}
222
223	function _convertPosition(&$x, &$y) // {{{2
224	{
225		// Parameters passed by ref!
226		$x = $this->_convertLength($x, 'width');
227		$y = $this->height - $this->_convertLength($y, 'height');
228	}
229
230	function _findStyle($name) // {{{2
231	{
232		$parts = explode('-', $name);
233		$style = [];
234
235		switch ($parts[0]) {
236			case 'Thin':
237				$style['line-width'] = 1;
238				array_shift($parts);
239				break;
240			case 'Bold':
241				$style['line-width'] = 2;
242				array_shift($parts);
243				break;
244			case 'Bolder':
245				$style['line-width'] = 3;
246				array_shift($parts);
247				break;
248			case 'Large':
249				$style['font'] = 16;
250				array_shift($parts);
251				break;
252			case 'Small':
253				$style['font'] = 8;
254				array_shift($parts);
255				break;
256			case 'Normal':
257				array_shift($parts);
258			default:
259				if ($parts[0] == 'Text') {
260					$style['font'] = 12;
261				} else {
262					$style['line-width'] = 1;
263				}
264				break;
265		}
266
267		switch ($parts[0]) {
268			case 'LineStroke':
269				$style['line'] = $this->_getColor($parts[1]);
270				break;
271			case 'FillStroke':
272				$style['fill'] = $this->_getColor($parts[1]);
273				$style['line'] = $this->_getColor('Black');
274				break;
275			case 'Text':
276				$style['fill'] = $this->_getColor('Black');
277				switch ($parts[1]) {
278					case 'Center':
279						$style['align'] = 'center';
280						break;
281					case 'Right':
282						$style['align'] = 'right';
283						break;
284					case 'Left':
285					default:
286						$style['align'] = 'left';
287						break;
288				}
289				break;
290			default:
291				return GRenderer::getStyle($name);
292		}
293
294		return $style;
295	}
296
297	function _getColor($name) // {{{2
298	{
299		$c = [ 'rgb' ];
300		$color = $this->_getRawColor(strtolower($name));
301		foreach ($color as $col) {
302			$c[] = $col / 255;
303		}
304
305		$c[] = null;
306
307		return $c;
308	}
309
310	function _getFormat($format, $orientation) // {{{2
311	{
312		/*
313			Taken from lib/pdflib/class.ezpdf.php
314			Copyright notices are in that file.
315		*/
316		switch (strtoupper($format)) {
317			case '4A0':
318				$size = [4767.87,6740.79];
319				break;
320			case '2A0':
321				$size = [3370.39,4767.87];
322				break;
323			case 'A0':
324				$size = [2383.94,3370.39];
325				break;
326			case 'A1':
327				$size = [1683.78,2383.94];
328				break;
329			case 'A2':
330				$size = [1190.55,1683.78];
331				break;
332			case 'A3':
333				$size = [841.89,1190.55];
334				break;
335			case 'A4':
336				$size = [595.28,841.89];
337				break;
338			case 'A5':
339				$size = [419.53,595.28];
340				break;
341			case 'A6':
342				$size = [297.64,419.53];
343				break;
344			case 'A7':
345				$size = [209.76,297.64];
346				break;
347			case 'A8':
348				$size = [147.40,209.76];
349				break;
350			case 'A9':
351				$size = [104.88,147.40];
352				break;
353			case 'A10':
354				$size = [73.70,104.88];
355				break;
356			case 'B0':
357				$size = [2834.65,4008.19];
358				break;
359			case 'B1':
360				$size = [2004.09,2834.65];
361				break;
362			case 'B2':
363				$size = [1417.32,2004.09];
364				break;
365			case 'B3':
366				$size = [1000.63,1417.32];
367				break;
368			case 'B4':
369				$size = [708.66,1000.63];
370				break;
371			case 'B5':
372				$size = [498.90,708.66];
373				break;
374			case 'B6':
375				$size = [354.33,498.90];
376				break;
377			case 'B7':
378				$size = [249.45,354.33];
379				break;
380			case 'B8':
381				$size = [175.75,249.45];
382				break;
383			case 'B9':
384				$size = [124.72,175.75];
385				break;
386			case 'B10':
387				$size = [87.87,124.72];
388				break;
389			case 'C0':
390				$size = [2599.37,3676.54];
391				break;
392			case 'C1':
393				$size = [1836.85,2599.37];
394				break;
395			case 'C2':
396				$size = [1298.27,1836.85];
397				break;
398			case 'C3':
399				$size = [918.43,1298.27];
400				break;
401			case 'C4':
402				$size = [649.13,918.43];
403				break;
404			case 'C5':
405				$size = [459.21,649.13];
406				break;
407			case 'C6':
408				$size = [323.15,459.21];
409				break;
410			case 'C7':
411				$size = [229.61,323.15];
412				break;
413			case 'C8':
414				$size = [161.57,229.61];
415				break;
416			case 'C9':
417				$size = [113.39,161.57];
418				break;
419			case 'C10':
420				$size = [79.37,113.39];
421				break;
422			case 'RA0':
423				$size = [2437.80,3458.27];
424				break;
425			case 'RA1':
426				$size = [1729.13,2437.80];
427				break;
428			case 'RA2':
429				$size = [1218.90,1729.13];
430				break;
431			case 'RA3':
432				$size = [864.57,1218.90];
433				break;
434			case 'RA4':
435				$size = [609.45,864.57];
436				break;
437			case 'SRA0':
438				$size = [2551.18,3628.35];
439				break;
440			case 'SRA1':
441				$size = [1814.17,2551.18];
442				break;
443			case 'SRA2':
444				$size = [1275.59,1814.17];
445				break;
446			case 'SRA3':
447				$size = [907.09,1275.59];
448				break;
449			case 'SRA4':
450				$size = [637.80,907.09];
451				break;
452			case 'LETTER':
453				$size = [612.00,792.00];
454				break;
455			case 'LEGAL':
456				$size = [612.00,1008.00];
457				break;
458			case 'EXECUTIVE':
459				$size = [521.86,756.00];
460				break;
461			case 'FOLIO':
462				$size = [612.00,936.00];
463				break;
464		}
465
466		if (strtolower($orientation) == 'landscape') {
467			$a = $size[1];
468			$size[1] = $size[0];
469			$size[0] = $a;
470		}
471
472		return $size;
473	}
474} // }}}1
475