4 * @link http://github.com/PhenX/php-svg-lib
5 * @author Fabien M�nager <fabien.menager@gmail.com>
6 * @license GNU LGPLv3+ http://www.gnu.org/copyleft/lesser.html
14 class SurfacePDFLib
implements SurfaceInterface
26 public function __construct(Document
$doc, $canvas = null)
28 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
30 $dimensions = $doc->getDimensions();
31 $w = $dimensions["width"];
32 $h = $dimensions["height"];
35 $canvas = new \
PDFlib();
37 /* all strings are expected as utf8 */
38 $canvas->set_option("stringformat=utf8");
39 $canvas->set_option("errorpolicy=return");
41 /* open new PDF file; insert a file name to create the PDF on disk */
42 if ($canvas->begin_document("", "") == 0) {
43 die("Error: " . $canvas->get_errmsg());
45 $canvas->set_info("Creator", "PDFlib starter sample");
46 $canvas->set_info("Title", "starter_graphics");
48 $canvas->begin_page_ext($w, $h, "");
51 // Flip PDF coordinate system so that the origin is in
52 // the top left rather than the bottom left
62 $this->canvas
= $canvas;
67 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
69 $this->canvas
->end_page_ext("");
70 $this->canvas
->end_document("");
72 return $this->canvas
->get_buffer();
75 public function save()
77 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
78 $this->canvas
->save();
81 public function restore()
83 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
84 $this->canvas
->restore();
87 public function scale($x, $y)
89 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
90 $this->canvas
->scale($x, $y);
93 public function rotate($angle)
95 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
96 $this->canvas
->rotate($angle);
99 public function translate($x, $y)
101 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
102 $this->canvas
->translate($x, $y);
105 public function transform($a, $b, $c, $d, $e, $f)
107 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
108 $this->canvas
->concat($a, $b, $c, $d, $e, $f);
111 public function beginPath()
113 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
114 // TODO: Implement beginPath() method.
117 public function closePath()
119 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
120 $this->canvas
->closepath();
123 public function fillStroke()
125 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
126 $this->canvas
->fill_stroke();
129 public function clip()
131 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
132 $this->canvas
->clip();
135 public function fillText($text, $x, $y, $maxWidth = null)
137 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
138 $this->canvas
->set_text_pos($x, $y);
139 $this->canvas
->show($text);
142 public function strokeText($text, $x, $y, $maxWidth = null)
144 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
145 // TODO: Implement drawImage() method.
148 public function drawImage($image, $sx, $sy, $sw = null, $sh = null, $dx = null, $dy = null, $dw = null, $dh = null)
150 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
152 if (strpos($image, "data:") === 0) {
153 $data = substr($image, strpos($image, ";") +
1);
154 if (strpos($data, "base64") === 0) {
155 $data = base64_decode(substr($data, 7));
159 $data = file_get_contents($image);
162 $image = tempnam("", "svg");
163 file_put_contents($image, $data);
165 $img = $this->canvas
->load_image("auto", $image, "");
168 $this->canvas
->fit_image($img, $sx, $sy, 'boxsize={' . "$sw $sh" . '} fitmethod=entire');
173 public function lineTo($x, $y)
175 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
176 $this->canvas
->lineto($x, $y);
179 public function moveTo($x, $y)
181 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
182 $this->canvas
->moveto($x, $y);
185 public function quadraticCurveTo($cpx, $cpy, $x, $y)
187 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
189 // FIXME not accurate
190 $this->canvas
->curveTo($cpx, $cpy, $cpx, $cpy, $x, $y);
193 public function bezierCurveTo($cp1x, $cp1y, $cp2x, $cp2y, $x, $y)
195 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
196 $this->canvas
->curveto($cp1x, $cp1y, $cp2x, $cp2y, $x, $y);
199 public function arcTo($x1, $y1, $x2, $y2, $radius)
201 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
204 public function arc($x, $y, $radius, $startAngle, $endAngle, $anticlockwise = false)
206 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
207 $this->canvas
->arc($x, $y, $radius, $startAngle, $endAngle);
210 public function circle($x, $y, $radius)
212 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
213 $this->canvas
->circle($x, $y, $radius);
216 public function ellipse($x, $y, $radiusX, $radiusY, $rotation, $startAngle, $endAngle, $anticlockwise)
218 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
219 $this->canvas
->ellipse($x, $y, $radiusX, $radiusY);
222 public function fillRect($x, $y, $w, $h)
224 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
225 $this->rect($x, $y, $w, $h);
229 public function rect($x, $y, $w, $h, $rx = 0, $ry = 0)
231 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
233 $canvas = $this->canvas
;
235 if ($rx <= 0.000001/* && $ry <= 0.000001*/) {
236 $canvas->rect($x, $y, $w, $h);
241 /* Define a path for a rectangle with corners rounded by a given radius.
242 * Start from the lower left corner and proceed counterclockwise.
244 $canvas->moveto($x +
$rx, $y);
246 /* Start of the arc segment in the lower right corner */
247 $canvas->lineto($x +
$w - $rx, $y);
249 /* Arc segment in the lower right corner */
250 $canvas->arc($x +
$w - $rx, $y +
$rx, $rx, 270, 360);
252 /* Start of the arc segment in the upper right corner */
253 $canvas->lineto($x +
$w, $y +
$h - $rx );
255 /* Arc segment in the upper right corner */
256 $canvas->arc($x +
$w - $rx, $y +
$h - $rx, $rx, 0, 90);
258 /* Start of the arc segment in the upper left corner */
259 $canvas->lineto($x +
$rx, $y +
$h);
261 /* Arc segment in the upper left corner */
262 $canvas->arc($x +
$rx, $y +
$h - $rx, $rx, 90, 180);
264 /* Start of the arc segment in the lower left corner */
265 $canvas->lineto($x , $y +
$rx);
267 /* Arc segment in the lower left corner */
268 $canvas->arc($x +
$rx, $y +
$rx, $rx, 180, 270);
271 public function fill()
273 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
274 $this->canvas
->fill();
277 public function strokeRect($x, $y, $w, $h)
279 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
280 $this->rect($x, $y, $w, $h);
284 public function stroke()
286 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
287 $this->canvas
->stroke();
290 public function endPath()
292 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
293 $this->canvas
->endPath();
296 public function measureText($text)
298 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
299 $style = $this->getStyle();
300 $font = $this->getFont($style->fontFamily
, $style->fontStyle
);
302 return $this->canvas
->stringwidth($text, $font, $this->getStyle()->fontSize
);
305 public function getStyle()
307 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
311 public function setStyle(Style
$style)
313 if (self
::DEBUG
) echo __FUNCTION__
. "\n";
315 $this->style
= $style;
316 $canvas = $this->canvas
;
318 if ($stroke = $style->stroke
&& is_array($style->stroke
)) {
329 if ($fill = $style->fill
&& is_array($style->fill
)) {
340 if ($fillRule = strtolower($style->fillRule
)) {
342 "nonzero" => "winding",
343 "evenodd" => "evenodd",
346 if (isset($map[$fillRule])) {
347 $fillRule = $map[$fillRule];
349 $canvas->set_parameter("fillrule", $fillRule);
354 if ($style->strokeWidth
> 0.000001) {
355 $opts[] = "linewidth=$style->strokeWidth";
358 if (in_array($style->strokeLinecap
, array("butt", "round", "projecting"))) {
359 $opts[] = "linecap=$style->strokeLinecap";
362 if (in_array($style->strokeLinejoin
, array("miter", "round", "bevel"))) {
363 $opts[] = "linejoin=$style->strokeLinejoin";
366 $canvas->set_graphics_option(implode(" ", $opts));
369 $opacity = $style->opacity
;
370 if ($opacity !== null && $opacity < 1.0) {
371 $opts[] = "opacityfill=$opacity";
372 $opts[] = "opacitystroke=$opacity";
375 $fillOpacity = $style->fillOpacity
;
376 if ($fillOpacity !== null && $fillOpacity < 1.0) {
377 $opts[] = "opacityfill=$fillOpacity";
380 $strokeOpacity = $style->strokeOpacity
;
381 if ($strokeOpacity !== null && $strokeOpacity < 1.0) {
382 $opts[] = "opacitystroke=$strokeOpacity";
387 $gs = $canvas->create_gstate(implode(" ", $opts));
388 $canvas->set_gstate($gs);
391 $font = $this->getFont($style->fontFamily
, $style->fontStyle
);
393 $canvas->setfont($font, $style->fontSize
);
397 private function getFont($family, $style)
401 "sans-serif" => "Helvetica",
402 "fantasy" => "Symbol",
403 "cursive" => "Times",
404 "monospace" => "Courier",
406 "arial" => "Helvetica",
407 "verdana" => "Helvetica",
410 $family = strtolower($family);
411 if (isset($map[$family])) {
412 $family = $map[$family];
415 return $this->canvas
->load_font($family, "unicode", "fontstyle=$style");
418 public function setFont($family, $style, $weight)
420 // TODO: Implement setFont() method.