commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-new / civicrm / vendor / dompdf / dompdf / src / Adapter / GD.php
1 <?php
2 /**
3 * @package dompdf
4 * @link http://dompdf.github.com/
5 * @author Benj Carson <benjcarson@digitaljunkies.ca>
6 * @author Fabien Ménager <fabien.menager@gmail.com>
7 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8 */
9 namespace Dompdf\Adapter;
10
11 use Dompdf\Canvas;
12 use Dompdf\Dompdf;
13 use Dompdf\Image\Cache;
14 use Dompdf\Helpers;
15
16 /**
17 * Image rendering interface
18 *
19 * Renders to an image format supported by GD (jpeg, gif, png, xpm).
20 * Not super-useful day-to-day but handy nonetheless
21 *
22 * @package dompdf
23 */
24 class GD implements Canvas
25 {
26 /**
27 * @var Dompdf
28 */
29 private $_dompdf;
30
31 /**
32 * Resource handle for the image
33 *
34 * @var resource
35 */
36 private $_img;
37
38 /**
39 * Resource handle for the image
40 *
41 * @var resource[]
42 */
43 private $_imgs;
44
45 /**
46 * Apparent canvas width in pixels
47 *
48 * @var int
49 */
50 private $_width;
51
52 /**
53 * Apparent canvas height in pixels
54 *
55 * @var int
56 */
57 private $_height;
58
59 /**
60 * Actual image width in pixels
61 *
62 * @var int
63 */
64 private $_actual_width;
65
66 /**
67 * Actual image height in pixels
68 *
69 * @var int
70 */
71 private $_actual_height;
72
73 /**
74 * Current page number
75 *
76 * @var int
77 */
78 private $_page_number;
79
80 /**
81 * Total number of pages
82 *
83 * @var int
84 */
85 private $_page_count;
86
87 /**
88 * Image antialias factor
89 *
90 * @var float
91 */
92 private $_aa_factor;
93
94 /**
95 * Allocated colors
96 *
97 * @var array
98 */
99 private $_colors;
100
101 /**
102 * Background color
103 *
104 * @var int
105 */
106 private $_bg_color;
107
108 /**
109 * Background color array
110 *
111 * @var int
112 */
113 private $_bg_color_array;
114
115 /**
116 * Actual DPI
117 *
118 * @var int
119 */
120 private $dpi;
121
122 /**
123 * Amount to scale font sizes
124 *
125 * Font sizes are 72 DPI, GD internally uses 96. Scale them proportionally.
126 * 72 / 96 = 0.75.
127 *
128 * @var float
129 */
130 const FONT_SCALE = 0.75;
131
132 /**
133 * Class constructor
134 *
135 * @param mixed $size The size of image to create: array(x1,y1,x2,y2) or "letter", "legal", etc.
136 * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
137 * @param Dompdf $dompdf
138 * @param float $aa_factor Anti-aliasing factor, 1 for no AA
139 * @param array $bg_color Image background color: array(r,g,b,a), 0 <= r,g,b,a <= 1
140 */
141 function __construct($size = 'letter', $orientation = "portrait", Dompdf $dompdf, $aa_factor = 1.0, $bg_color = array(1, 1, 1, 0))
142 {
143
144 if (!is_array($size)) {
145 $size = strtolower($size);
146
147 if (isset(CPDF::$PAPER_SIZES[$size])) {
148 $size = CPDF::$PAPER_SIZES[$size];
149 } else {
150 $size = CPDF::$PAPER_SIZES["letter"];
151 }
152 }
153
154 if (strtolower($orientation) === "landscape") {
155 list($size[2], $size[3]) = array($size[3], $size[2]);
156 }
157
158 $this->_dompdf = $dompdf;
159
160 $this->dpi = $this->get_dompdf()->get_option('dpi');
161
162 if ($aa_factor < 1) {
163 $aa_factor = 1;
164 }
165
166 $this->_aa_factor = $aa_factor;
167
168 $size[2] *= $aa_factor;
169 $size[3] *= $aa_factor;
170
171 $this->_width = $size[2] - $size[0];
172 $this->_height = $size[3] - $size[1];
173
174 $this->_actual_width = $this->_upscale($this->_width);
175 $this->_actual_height = $this->_upscale($this->_height);
176
177 if (is_null($bg_color) || !is_array($bg_color)) {
178 // Pure white bg
179 $bg_color = array(1, 1, 1, 0);
180 }
181
182 $this->_bg_color_array = $bg_color;
183
184 $this->new_page();
185 }
186
187 function get_dompdf()
188 {
189 return $this->_dompdf;
190 }
191
192 /**
193 * Return the GF image resource
194 *
195 * @return resource
196 */
197 function get_image()
198 {
199 return $this->_img;
200 }
201
202 /**
203 * Return the image's width in pixels
204 *
205 * @return float
206 */
207 function get_width()
208 {
209 return $this->_width / $this->_aa_factor;
210 }
211
212 /**
213 * Return the image's height in pixels
214 *
215 * @return float
216 */
217 function get_height()
218 {
219 return $this->_height / $this->_aa_factor;
220 }
221
222 /**
223 * Returns the current page number
224 * @return int
225 */
226 function get_page_number()
227 {
228 return $this->_page_number;
229 }
230
231 /**
232 * Returns the total number of pages in the document
233 * @return int
234 */
235 function get_page_count()
236 {
237 return $this->_page_count;
238 }
239
240 /**
241 * Sets the current page number
242 *
243 * @param int $num
244 */
245 function set_page_number($num)
246 {
247 $this->_page_number = $num;
248 }
249
250 /**
251 * Sets the page count
252 *
253 * @param int $count
254 */
255 function set_page_count($count)
256 {
257 $this->_page_count = $count;
258 }
259
260 /**
261 * Sets the opacity
262 *
263 * @param $opacity
264 * @param $mode
265 */
266 function set_opacity($opacity, $mode = "Normal")
267 {
268 // FIXME
269 }
270
271 /**
272 * Allocate a new color. Allocate with GD as needed and store
273 * previously allocated colors in $this->_colors.
274 *
275 * @param array $color The new current color
276 * @return int The allocated color
277 */
278 private function _allocate_color($color)
279 {
280
281 if (isset($color["c"])) {
282 $color = Helpers::cmyk_to_rgb($color);
283 }
284
285 // Full opacity if no alpha set
286 if (!isset($color[3]))
287 $color[3] = 0;
288
289 list($r, $g, $b, $a) = $color;
290
291 $r *= 255;
292 $g *= 255;
293 $b *= 255;
294 $a *= 127;
295
296 // Clip values
297 $r = $r > 255 ? 255 : $r;
298 $g = $g > 255 ? 255 : $g;
299 $b = $b > 255 ? 255 : $b;
300 $a = $a > 127 ? 127 : $a;
301
302 $r = $r < 0 ? 0 : $r;
303 $g = $g < 0 ? 0 : $g;
304 $b = $b < 0 ? 0 : $b;
305 $a = $a < 0 ? 0 : $a;
306
307 $key = sprintf("#%02X%02X%02X%02X", $r, $g, $b, $a);
308
309 if (isset($this->_colors[$key]))
310 return $this->_colors[$key];
311
312 if ($a != 0)
313 $this->_colors[$key] = imagecolorallocatealpha($this->get_image(), $r, $g, $b, $a);
314 else
315 $this->_colors[$key] = imagecolorallocate($this->get_image(), $r, $g, $b);
316
317 return $this->_colors[$key];
318
319 }
320
321 /**
322 * Scales value up to the current canvas DPI from 72 DPI
323 *
324 * @param float $length
325 * @return float
326 */
327 private function _upscale($length)
328 {
329 return ($length * $this->dpi) / 72 * $this->_aa_factor;
330 }
331
332 /**
333 * Scales value down from the current canvas DPI to 72 DPI
334 *
335 * @param float $length
336 * @return float
337 */
338 private function _downscale($length)
339 {
340 return ($length / $this->dpi * 72) / $this->_aa_factor;
341 }
342
343 /**
344 * Draws a line from x1,y1 to x2,y2
345 *
346 * See {@link Style::munge_color()} for the format of the color array.
347 * See {@link Cpdf::setLineStyle()} for a description of the format of the
348 * $style parameter (aka dash).
349 *
350 * @param float $x1
351 * @param float $y1
352 * @param float $x2
353 * @param float $y2
354 * @param array $color
355 * @param float $width
356 * @param array $style
357 */
358 function line($x1, $y1, $x2, $y2, $color, $width, $style = null)
359 {
360
361 // Scale by the AA factor and DPI
362 $x1 = $this->_upscale($x1);
363 $y1 = $this->_upscale($y1);
364 $x2 = $this->_upscale($x2);
365 $y2 = $this->_upscale($y2);
366 $width = $this->_upscale($width);
367
368 $c = $this->_allocate_color($color);
369
370 // Convert the style array if required
371 if (is_array($style) && count($style) > 0) {
372 $gd_style = array();
373
374 if (count($style) == 1) {
375 for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
376 $gd_style[] = $c;
377 }
378
379 for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
380 $gd_style[] = $this->_bg_color;
381 }
382
383 } else {
384
385 $i = 0;
386 foreach ($style as $length) {
387
388 if ($i % 2 == 0) {
389 // 'On' pattern
390 for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
391 $gd_style[] = $c;
392
393 } else {
394 // Off pattern
395 for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
396 $gd_style[] = $this->_bg_color;
397
398 }
399 $i++;
400 }
401 }
402
403 if(!empty($gd_style)) {
404 imagesetstyle($this->get_image(), $gd_style);
405 $c = IMG_COLOR_STYLED;
406 }
407 }
408
409 imagesetthickness($this->get_image(), $width);
410
411 imageline($this->get_image(), $x1, $y1, $x2, $y2, $c);
412
413 }
414
415 function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = array())
416 {
417 // @todo
418 }
419
420 /**
421 * Draws a rectangle at x1,y1 with width w and height h
422 *
423 * See {@link Style::munge_color()} for the format of the color array.
424 * See {@link Cpdf::setLineStyle()} for a description of the $style
425 * parameter (aka dash)
426 *
427 * @param float $x1
428 * @param float $y1
429 * @param float $w
430 * @param float $h
431 * @param array $color
432 * @param float $width
433 * @param array $style
434 */
435 function rectangle($x1, $y1, $w, $h, $color, $width, $style = null)
436 {
437
438 // Scale by the AA factor and DPI
439 $x1 = $this->_upscale($x1);
440 $y1 = $this->_upscale($y1);
441 $w = $this->_upscale($w);
442 $h = $this->_upscale($h);
443 $width = $this->_upscale($width);
444
445 $c = $this->_allocate_color($color);
446
447 // Convert the style array if required
448 if (is_array($style) && count($style) > 0) {
449 $gd_style = array();
450
451 foreach ($style as $length) {
452 for ($i = 0; $i < $length; $i++) {
453 $gd_style[] = $c;
454 }
455 }
456
457 if(!empty($gd_style)) {
458 imagesetstyle($this->get_image(), $gd_style);
459 $c = IMG_COLOR_STYLED;
460 }
461 }
462
463 imagesetthickness($this->get_image(), $width);
464
465 imagerectangle($this->get_image(), $x1, $y1, $x1 + $w, $y1 + $h, $c);
466
467 }
468
469 /**
470 * Draws a filled rectangle at x1,y1 with width w and height h
471 *
472 * See {@link Style::munge_color()} for the format of the color array.
473 *
474 * @param float $x1
475 * @param float $y1
476 * @param float $w
477 * @param float $h
478 * @param array $color
479 */
480 function filled_rectangle($x1, $y1, $w, $h, $color)
481 {
482
483 // Scale by the AA factor and DPI
484 $x1 = $this->_upscale($x1);
485 $y1 = $this->_upscale($y1);
486 $w = $this->_upscale($w);
487 $h = $this->_upscale($h);
488
489 $c = $this->_allocate_color($color);
490
491 imagefilledrectangle($this->get_image(), $x1, $y1, $x1 + $w, $y1 + $h, $c);
492
493 }
494
495 /**
496 * Starts a clipping rectangle at x1,y1 with width w and height h
497 *
498 * @param float $x1
499 * @param float $y1
500 * @param float $w
501 * @param float $h
502 */
503 function clipping_rectangle($x1, $y1, $w, $h)
504 {
505 // @todo
506 }
507
508 function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
509 {
510 // @todo
511 }
512
513 /**
514 * Ends the last clipping shape
515 */
516 function clipping_end()
517 {
518 // @todo
519 }
520
521 function save()
522 {
523 $this->get_dompdf()->set_option('dpi', 72);
524 }
525
526 function restore()
527 {
528 $this->get_dompdf()->set_option('dpi', $this->dpi);
529 }
530
531 function rotate($angle, $x, $y)
532 {
533 // @todo
534 }
535
536 function skew($angle_x, $angle_y, $x, $y)
537 {
538 // @todo
539 }
540
541 function scale($s_x, $s_y, $x, $y)
542 {
543 // @todo
544 }
545
546 function translate($t_x, $t_y)
547 {
548 // @todo
549 }
550
551 function transform($a, $b, $c, $d, $e, $f)
552 {
553 // @todo
554 }
555
556 /**
557 * Draws a polygon
558 *
559 * The polygon is formed by joining all the points stored in the $points
560 * array. $points has the following structure:
561 * <code>
562 * array(0 => x1,
563 * 1 => y1,
564 * 2 => x2,
565 * 3 => y2,
566 * ...
567 * );
568 * </code>
569 *
570 * See {@link Style::munge_color()} for the format of the color array.
571 * See {@link Cpdf::setLineStyle()} for a description of the $style
572 * parameter (aka dash)
573 *
574 * @param array $points
575 * @param array $color
576 * @param float $width
577 * @param array $style
578 * @param bool $fill Fills the polygon if true
579 */
580 function polygon($points, $color, $width = null, $style = null, $fill = false)
581 {
582
583 // Scale each point by the AA factor and DPI
584 foreach (array_keys($points) as $i)
585 $points[$i] = $this->_upscale($points[$i]);
586
587 $c = $this->_allocate_color($color);
588
589 // Convert the style array if required
590 if (is_array($style) && count($style) > 0 && !$fill) {
591 $gd_style = array();
592
593 foreach ($style as $length) {
594 for ($i = 0; $i < $length; $i++) {
595 $gd_style[] = $c;
596 }
597 }
598
599 if(!empty($gd_style)) {
600 imagesetstyle($this->get_image(), $gd_style);
601 $c = IMG_COLOR_STYLED;
602 }
603 }
604
605 imagesetthickness($this->get_image(), $width);
606
607 if ($fill)
608 imagefilledpolygon($this->get_image(), $points, count($points) / 2, $c);
609 else
610 imagepolygon($this->get_image(), $points, count($points) / 2, $c);
611
612 }
613
614 /**
615 * Draws a circle at $x,$y with radius $r
616 *
617 * See {@link Style::munge_color()} for the format of the color array.
618 * See {@link Cpdf::setLineStyle()} for a description of the $style
619 * parameter (aka dash)
620 *
621 * @param float $x
622 * @param float $y
623 * @param float $r
624 * @param array $color
625 * @param float $width
626 * @param array $style
627 * @param bool $fill Fills the circle if true
628 */
629 function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false)
630 {
631
632 // Scale by the AA factor and DPI
633 $x = $this->_upscale($x);
634 $y = $this->_upscale($y);
635 $r = $this->_upscale($r);
636
637 $c = $this->_allocate_color($color);
638
639 // Convert the style array if required
640 if (is_array($style) && count($style) > 0 && !$fill) {
641 $gd_style = array();
642
643 foreach ($style as $length) {
644 for ($i = 0; $i < $length; $i++) {
645 $gd_style[] = $c;
646 }
647 }
648
649 if(!empty($gd_style)) {
650 imagesetstyle($this->get_image(), $gd_style);
651 $c = IMG_COLOR_STYLED;
652 }
653 }
654
655 imagesetthickness($this->get_image(), $width);
656
657 if ($fill)
658 imagefilledellipse($this->get_image(), $x, $y, $r, $r, $c);
659 else
660 imageellipse($this->get_image(), $x, $y, $r, $r, $c);
661
662 }
663
664 /**
665 * Add an image to the pdf.
666 * The image is placed at the specified x and y coordinates with the
667 * given width and height.
668 *
669 * @param string $img_url the path to the image
670 * @param float $x x position
671 * @param float $y y position
672 * @param int $w width (in pixels)
673 * @param int $h height (in pixels)
674 * @param string $resolution
675 *
676 * @return void
677 * @internal param string $img_type the type (e.g. extension) of the image
678 */
679 function image($img_url, $x, $y, $w, $h, $resolution = "normal")
680 {
681 $img_type = Cache::detect_type($img_url, $this->get_dompdf()->getHttpContext());
682
683 if (!$img_type) {
684 return;
685 }
686
687 $func = "imagecreatefrom$img_type";
688 if (!function_exists($func_name)) {
689 if (!method_exists("Dompdf\Helpers", $func_name)) {
690 throw new Exception("Function $func_name() not found. Cannot convert $type image: $image_url. Please install the image PHP extension.");
691 }
692 $func_name = "\\Dompdf\\Helpers::" . $func_name;
693 }
694 $src = @call_user_func($func_name, $image_url);
695
696 if (!$src) {
697 return; // Probably should add to $_dompdf_errors or whatever here
698 }
699
700 // Scale by the AA factor and DPI
701 $x = $this->_upscale($x);
702 $y = $this->_upscale($y);
703
704 $w = $this->_upscale($w);
705 $h = $this->_upscale($h);
706
707 $img_w = imagesx($src);
708 $img_h = imagesy($src);
709
710 imagecopyresampled($this->get_image(), $src, $x, $y, 0, 0, $w, $h, $img_w, $img_h);
711
712 }
713
714 /**
715 * Writes text at the specified x and y coordinates
716 * See {@link Style::munge_color()} for the format of the color array.
717 *
718 * @param float $x
719 * @param float $y
720 * @param string $text the text to write
721 * @param string $font the font file to use
722 * @param float $size the font size, in points
723 * @param array $color
724 * @param float $word_spacing word spacing adjustment
725 * @param float $char_spacing
726 * @param float $angle Text angle
727 *
728 * @return void
729 */
730 function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_spacing = 0.0, $char_spacing = 0.0, $angle = 0.0)
731 {
732
733 // Scale by the AA factor and DPI
734 $x = $this->_upscale($x);
735 $y = $this->_upscale($y);
736 $size = $this->_upscale($size) * self::FONT_SCALE;
737
738 $h = $this->get_font_height_actual($font, $size);
739 $c = $this->_allocate_color($color);
740
741 // imagettftext() converts numeric entities to their respective
742 // character. Preserve any originally double encoded entities to be
743 // represented as is.
744 // eg: &amp;#160; will render &#160; rather than its character.
745 $text = preg_replace('/&(#(?:x[a-fA-F0-9]+|[0-9]+);)/', '&#38;\1', $text);
746
747 $text = mb_encode_numericentity($text, array(0x0080, 0xff, 0, 0xff), 'UTF-8');
748
749 $font = $this->get_ttf_file($font);
750
751 // FIXME: word spacing
752 imagettftext($this->get_image(), $size, $angle, $x, $y + $h, $c, $font, $text);
753
754 }
755
756 function javascript($code)
757 {
758 // Not implemented
759 }
760
761 /**
762 * Add a named destination (similar to <a name="foo">...</a> in html)
763 *
764 * @param string $anchorname The name of the named destination
765 */
766 function add_named_dest($anchorname)
767 {
768 // Not implemented
769 }
770
771 /**
772 * Add a link to the pdf
773 *
774 * @param string $url The url to link to
775 * @param float $x The x position of the link
776 * @param float $y The y position of the link
777 * @param float $width The width of the link
778 * @param float $height The height of the link
779 */
780 function add_link($url, $x, $y, $width, $height)
781 {
782 // Not implemented
783 }
784
785 /**
786 * Add meta information to the PDF
787 *
788 * @param string $label label of the value (Creator, Producer, etc.)
789 * @param string $value the text to set
790 */
791 function add_info($label, $value)
792 {
793 // N/A
794 }
795
796 function set_default_view($view, $options = array())
797 {
798 // N/A
799 }
800
801 /**
802 * Calculates text size, in points
803 *
804 * @param string $text the text to be sized
805 * @param string $font the desired font
806 * @param float $size the desired font size
807 * @param float $word_spacing word spacing, if any
808 * @param float $char_spacing char spacing, if any
809 *
810 * @return float
811 */
812 function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0)
813 {
814 $font = $this->get_ttf_file($font);
815 $size = $this->_upscale($size) * self::FONT_SCALE;
816
817 // imagettfbbox() converts numeric entities to their respective
818 // character. Preserve any originally double encoded entities to be
819 // represented as is.
820 // eg: &amp;#160; will render &#160; rather than its character.
821 $text = preg_replace('/&(#(?:x[a-fA-F0-9]+|[0-9]+);)/', '&#38;\1', $text);
822
823 $text = mb_encode_numericentity($text, array(0x0080, 0xffff, 0, 0xffff), 'UTF-8');
824
825 // FIXME: word spacing
826 list($x1, , $x2) = imagettfbbox($size, 0, $font, $text);
827
828 // Add additional 1pt to prevent text overflow issues
829 return $this->_downscale($x2 - $x1) + 1;
830 }
831
832 function get_ttf_file($font)
833 {
834 if (strpos($font, '.ttf') === false)
835 $font .= ".ttf";
836
837 /*$filename = substr(strtolower(basename($font)), 0, -4);
838
839 if ( in_array($filename, Dompdf::$native_fonts) ) {
840 return "arial.ttf";
841 }*/
842
843 return $font;
844 }
845
846 /**
847 * Calculates font height, in points
848 *
849 * @param string $font
850 * @param float $size
851 * @return float
852 */
853 function get_font_height($font, $size)
854 {
855 $size = $this->_upscale($size) * self::FONT_SCALE;
856
857 $height = $this->get_font_height_actual($font, $size);
858
859 return $this->_downscale($height);
860 }
861
862 private function get_font_height_actual($font, $size)
863 {
864 $font = $this->get_ttf_file($font);
865 $ratio = $this->_dompdf->get_option("font_height_ratio");
866
867 // FIXME: word spacing
868 list(, $y2, , , , $y1) = imagettfbbox($size, 0, $font, "MXjpqytfhl"); // Test string with ascenders, descenders and caps
869 return ($y2 - $y1) * $ratio;
870 }
871
872 function get_font_baseline($font, $size)
873 {
874 $ratio = $this->_dompdf->get_option("font_height_ratio");
875 return $this->get_font_height($font, $size) / $ratio;
876 }
877
878 /**
879 * Starts a new page
880 *
881 * Subsequent drawing operations will appear on the new page.
882 */
883 function new_page()
884 {
885 $this->_page_number++;
886 $this->_page_count++;
887
888 $this->_img = imagecreatetruecolor($this->_actual_width, $this->_actual_height);
889
890 $this->_bg_color = $this->_allocate_color($this->_bg_color_array);
891 imagealphablending($this->_img, true);
892 imagesavealpha($this->_img, true);
893 imagefill($this->_img, 0, 0, $this->_bg_color);
894
895 $this->_imgs[] = $this->_img;
896 }
897
898 function open_object()
899 {
900 // N/A
901 }
902
903 function close_object()
904 {
905 // N/A
906 }
907
908 function add_object()
909 {
910 // N/A
911 }
912
913 function page_text()
914 {
915 // N/A
916 }
917
918 /**
919 * Streams the image directly to the browser
920 *
921 * @param string $filename the name of the image file (ignored)
922 * @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
923 */
924 function stream($filename, $options = null)
925 {
926
927 $img = $this->_imgs[0];
928
929 if (isset($options['page']) && isset($this->_imgs[$options['page'] - 1])) {
930 $img = $this->_imgs[$options['page'] - 1];
931 }
932
933 // Perform any antialiasing
934 if ($this->_aa_factor != 1) {
935 $dst_w = $this->_actual_width / $this->_aa_factor;
936 $dst_h = $this->_actual_height / $this->_aa_factor;
937 $dst = imagecreatetruecolor($dst_w, $dst_h);
938 imagecopyresampled($dst, $img, 0, 0, 0, 0,
939 $dst_w, $dst_h,
940 $this->_actual_width, $this->_actual_height);
941 } else {
942 $dst = $img;
943 }
944
945 if (!isset($options["type"]))
946 $options["type"] = "png";
947
948 $type = strtolower($options["type"]);
949
950 header("Cache-Control: private");
951
952 $filename = str_replace(array("\n", "'"), "", basename($filename));
953 switch ($type) {
954
955 case "jpg":
956 case "jpeg":
957 $filename .= ".jpg";
958 break;
959
960 case "png":
961 default:
962 $filename .= ".png";
963 break;
964 }
965 $attach = (isset($options["Attachment"]) && $options["Attachment"]) ? "attachment" : "inline";
966
967 // detect the character encoding of the incoming file
968 $encoding = mb_detect_encoding($filename);
969 $fallbackfilename = mb_convert_encoding($filename, "ISO-8859-1", $encoding);
970 $encodedfallbackfilename = rawurlencode($fallbackfilename);
971 $encodedfilename = rawurlencode($filename);
972
973 header("Content-Disposition: $attach; filename=". $encodedfallbackfilename ."; filename*=UTF-8''$encodedfilename");
974
975 switch ($type) {
976
977 case "jpg":
978 case "jpeg":
979 if (!isset($options["quality"]))
980 $options["quality"] = 75;
981
982 header("Content-type: image/jpeg");
983 imagejpeg($dst, '', $options["quality"]);
984 break;
985
986 case "png":
987 default:
988 header("Content-type: image/png");
989 imagepng($dst);
990 break;
991 }
992
993 if ($this->_aa_factor != 1)
994 imagedestroy($dst);
995 }
996
997 /**
998 * Returns the PNG as a string
999 *
1000 * @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
1001 * @return string
1002 */
1003 function output($options = null)
1004 {
1005
1006 $img = $this->_imgs[0];
1007
1008 if (isset($options['page']) && isset($this->_imgs[$options['page'] - 1])) {
1009 $img = $this->_imgs[$options['page'] - 1];
1010 }
1011
1012 if ($this->_aa_factor != 1) {
1013 $dst_w = $this->_actual_width / $this->_aa_factor;
1014 $dst_h = $this->_actual_height / $this->_aa_factor;
1015 $dst = imagecreatetruecolor($dst_w, $dst_h);
1016 imagecopyresampled($dst, $img, 0, 0, 0, 0,
1017 $dst_w, $dst_h,
1018 $this->_actual_width, $this->_actual_height);
1019 } else {
1020 $dst = $img;
1021 }
1022
1023 if (!isset($options["type"]))
1024 $options["type"] = "png";
1025
1026 $type = $options["type"];
1027
1028 ob_start();
1029
1030 switch ($type) {
1031
1032 case "jpg":
1033 case "jpeg":
1034 if (!isset($options["quality"]))
1035 $options["quality"] = 75;
1036
1037 imagejpeg($dst, '', $options["quality"]);
1038 break;
1039
1040 case "png":
1041 default:
1042 imagepng($dst);
1043 break;
1044 }
1045
1046 $image = ob_get_clean();
1047
1048 if ($this->_aa_factor != 1)
1049 imagedestroy($dst);
1050
1051 return $image;
1052 }
1053
1054
1055 }