linea21-externals
[ class tree: linea21-externals ] [ index: linea21-externals ] [ all elements ]

Source for file gd.class.php

Documentation is available at gd.class.php

  1. <?php
  2. /*
  3.  * This work is hereby released into the Public Domain.
  4.  * To view a copy of the public domain dedication,
  5.  * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
  6.  * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
  7.  *
  8.  */
  9.  
  10. require_once dirname(__FILE__)."/../Driver.class.php";
  11.  
  12. /**
  13.  * Draw your objects
  14.  *
  15.  * @package linea21.externals
  16.  * @subpackage artichow
  17.  */
  18.  
  19. class awGDDriver extends Driver {
  20.  
  21.   /**
  22.    * A GD resource
  23.    *
  24.    * @var $resource 
  25.    */
  26.   public $resource;
  27.  
  28.   public function __construct() {
  29.     parent::__construct();
  30.  
  31.     $this->driverString = 'gd';
  32.   }
  33.  
  34.   public function init(awImage $image) {
  35.  
  36.     if($this->resource === NULL) {
  37.           
  38.       $this->setImageSize($image->width, $image->height);
  39.           
  40.       // Create image
  41.       $this->resource = imagecreatetruecolor($this->imageWidth, $this->imageHeight);
  42.       if(!$this->resource) {
  43.         awImage::drawError("Class Image: Unable to create a graph.");
  44.       }
  45.           
  46.       imagealphablending($this->resource, TRUE);
  47.           
  48.       // Antialiasing is now handled by the Driver object
  49.       $this->setAntiAliasing($image->getAntiAliasing());
  50.           
  51.       // Original color
  52.       $this->filledRectangle(
  53.       new awWhite,
  54.       new awLine(
  55.       new awPoint(0, 0),
  56.       new awPoint($this->imageWidth, $this->imageHeight)
  57.       )
  58.       );
  59.           
  60.       $shadow = $image->shadow;
  61.       if($shadow !== NULL) {
  62.         $shadow = $shadow->getSpace();
  63.         $p1 = new awPoint($shadow->left, $shadow->top);
  64.         $p2 = new awPoint($this->imageWidth - $shadow->right - 1, $this->imageHeight - $shadow->bottom - 1);
  65.  
  66.  
  67.         // Draw image background
  68.         $this->filledRectangle($image->getBackground(), new awLine($p1, $p2));
  69.  
  70.         // Draw image border
  71.         $image->border->rectangle($this, $p1, $p2);
  72.       }
  73.           
  74.     }
  75.   }
  76.  
  77.   public function initFromFile(awFileImage $fileImage, $file) {
  78.  
  79.     $image = @getimagesize((string)$file);
  80.  
  81.     if($image and in_array($image[2], array(2, 3))) {
  82.  
  83.       $fileImage->setSize($image[0], $image[1]);
  84.           
  85.       switch($image[2]) {
  86.             
  87.         case 2 :
  88.           $this->resource = imagecreatefromjpeg($file);
  89.           break;
  90.               
  91.         case 3 :
  92.           $this->resource = imagecreatefrompng($file);
  93.           break;
  94.               
  95.       }
  96.  
  97.       $this->setImageSize($fileImage->width, $fileImage->height);
  98.     } else {
  99.       awImage::drawError("Class FileImage: Artichow does not support the format of this image (must be in PNG or JPEG)");
  100.     }
  101.   }
  102.  
  103.   public function setImageSize($width, $height) {
  104.  
  105.     $this->imageWidth = $width;
  106.     $this->imageHeight = $height;
  107.  
  108.   }
  109.  
  110.   public function setPosition($x, $y) {
  111.  
  112.     // Calculate absolute position
  113.     $this->x = round($x * $this->imageWidth - $this->w / 2);
  114.     $this->y = round($y * $this->imageHeight - $this->h / 2);
  115.  
  116.   }
  117.  
  118.   public function setAbsPosition($x, $y) {
  119.  
  120.     $this->x = $x;
  121.     $this->y = $y;
  122.  
  123.   }
  124.  
  125.   public function movePosition($x, $y) {
  126.  
  127.     $this->x += (int)$x;
  128.     $this->y += (int)$y;
  129.  
  130.   }
  131.  
  132.   public function setSize($w, $h) {
  133.  
  134.     // Calcul absolute size
  135.     $this->w = round($w * $this->imageWidth);
  136.     $this->h = round($h * $this->imageHeight);
  137.  
  138.     return $this->getSize();
  139.  
  140.   }
  141.  
  142.   public function setAbsSize($w, $h) {
  143.  
  144.     $this->w = $w;
  145.     $this->h = $h;
  146.  
  147.     return $this->getSize();
  148.  
  149.   }
  150.  
  151.   public function getSize() {
  152.  
  153.     return array($this->w, $this->h);
  154.  
  155.   }
  156.  
  157.   public function setAntiAliasing($bool) {
  158.  
  159.     if(function_exists('imageantialias')) {
  160.       imageantialias($this->resource, (bool)$bool);
  161.  
  162.       $this->antiAliasing = (bool)$bool;
  163.     } elseif($bool == true) {
  164.       awImage::drawErrorFile('missing-anti-aliasing');
  165.     }
  166.   }
  167.  
  168.   public function getColor(awColor $color) {
  169.  
  170.     if($color->alpha === 0 or function_exists('imagecolorallocatealpha') === FALSE) {
  171.       $gdColor = imagecolorallocate($this->resource, $color->red, $color->green, $color->blue);
  172.     } else {
  173.       $gdColor = imagecolorallocatealpha($this->resource, $color->red, $color->green, $color->blue, $color->alpha);
  174.     }
  175.  
  176.     return $gdColor;
  177.   }
  178.  
  179.   public function copyImage(awImage $image, awPoint $p1, awPoint $p2) {
  180.  
  181.     list($x1, $y1) = $p1->getLocation();
  182.     list($x2, $y2) = $p2->getLocation();
  183.  
  184.     $driver = $image->getDriver();
  185.     imagecopy($this->resource, $driver->resource, $this->x + $x1, $this->y + $y1, 0, 0, $x2 - $x1, $y2 - $y1);
  186.  
  187.   }
  188.  
  189.   public function copyResizeImage(awImage $image, awPoint $d1, awPoint $d2, awPoint $s1, awPoint $s2, $resample = TRUE) {
  190.  
  191.     if($resample) {
  192.       $function = 'imagecopyresampled';
  193.     } else {
  194.       $function = 'imagecopyresized';
  195.     }
  196.  
  197.     $driver = $image->getDriver();
  198.  
  199.     $function(
  200.     $this->resource,
  201.     $driver->resource,
  202.     $this->x + $d1->x, $this->y + $d1->y,
  203.     $s1->x, $s1->y,
  204.     $d2->x - $d1->x, $d2->y - $d1->y,
  205.     $s2->x - $s1->x, $s2->y - $s1->y
  206.     );
  207.  
  208.   }
  209.  
  210.   public function string(awText $text, awPoint $point, $width = NULL) {
  211.  
  212.     $font = $text->getFont();
  213.  
  214.     // Can we deal with that font?
  215.     /**
  216.     if($this->isCompatibleWithFont($font) === FALSE) {
  217.     awImage::drawError('Class GDDriver: Incompatible font type (\''.get_class($font).'\')');
  218.     }*/
  219.  
  220.     // Check which FontDriver to use
  221.     if($font instanceof awPHPFont) {
  222.       $fontDriver = $this->phpFontDriver;
  223.     } else {
  224.       $fontDriver = $this->fileFontDriver;
  225.     }
  226.  
  227.     if($text->getBackground() !== NULL or $text->border->visible()) {
  228.  
  229.       list($left, $right, $top, $bottom) = $text->getPadding();
  230.  
  231.       $textWidth = $fontDriver->getTextWidth($text, $this);
  232.       $textHeight = $fontDriver->getTextHeight($text, $this);
  233.           
  234.       $x1 = floor($point->x - $left);
  235.       $y1 = floor($point->y - $top);
  236.       $x2 = $x1 + $textWidth + $left + $right;
  237.       $y2 = $y1 + $textHeight + $top + $bottom;
  238.           
  239.       $this->filledRectangle(
  240.       $text->getBackground(),
  241.       awLine::build($x1, $y1, $x2, $y2)
  242.       );
  243.           
  244.       $text->border->rectangle(
  245.       $this,
  246.       new awPoint($x1 - 1, $y1 - 1),
  247.       new awPoint($x2 + 1, $y2 + 1)
  248.       );
  249.           
  250.     }
  251.  
  252.     $fontDriver->string($this, $text, $point, $width);
  253.  
  254.   }
  255.  
  256.   public function point(awColor $color, awPoint $p) {
  257.  
  258.     if($p->isHidden() === FALSE) {
  259.       $rgb = $this->getColor($color);
  260.       imagesetpixel($this->resource, $this->x + round($p->x), $this->y + round($p->y), $rgb);
  261.     }
  262.  
  263.   }
  264.  
  265.   public function line(awColor $color, awLine $line) {
  266.  
  267.     if($line->thickness > 0 and $line->isHidden() === FALSE) {
  268.  
  269.       $rgb = $this->getColor($color);
  270.       $thickness = $line->thickness;
  271.           
  272.       list($p1, $p2) = $line->getLocation();
  273.           
  274.       $this->startThickness($thickness);
  275.           
  276.       switch($line->getStyle()) {
  277.             
  278.         case awLine::SOLID :
  279.           imageline($this->resource, $this->x + round($p1->x), $this->y + round($p1->y), $this->x + round($p2->x), $this->y + round($p2->y), $rgb);
  280.           break;
  281.               
  282.         case awLine::DOTTED :
  283.           $size = sqrt(pow($p2->y - $p1->y, 2) + pow($p2->x - $p1->x, 2));
  284.           $cos = ($p2->x - $p1->x) / $size;
  285.           $sin = ($p2->y - $p1->y) / $size;
  286.           for($i = 0; $i <= $size; $i += 2) {
  287.             $p = new awPoint(
  288.             round($i * $cos + $p1->x),
  289.             round($i * $sin + $p1->y)
  290.             );
  291.             $this->point($color, $p);
  292.           }
  293.           break;
  294.               
  295.         case awLine::DASHED :
  296.           $width = $p2->x - $p1->x;
  297.           $height = $p2->y - $p1->y;
  298.           $size = sqrt(pow($height, 2) + pow($width, 2));
  299.               
  300.           if($size == 0) {
  301.             return;
  302.           }
  303.               
  304.           $cos = $width / $size;
  305.           $sin = $height / $size;
  306.               
  307.           $functionX = ($width  > 0) ? 'min' : 'max';
  308.           $functionY = ($height > 0) ? 'min' : 'max';
  309.               
  310.           for($i = 0; $i <= $size; $i += 6) {
  311.  
  312.             $t1 = new awPoint(
  313.             round($i * $cos + $p1->x),
  314.             round($i * $sin + $p1->y)
  315.             );
  316.  
  317.             $t2 = new awPoint(
  318.             round($functionX(($i + 3) * $cos, $width) + $p1->x),
  319.             round($functionY(($i + 3) * $sin, $height) + $p1->y)
  320.             );
  321.  
  322.             $this->line($color, new awLine($t1, $t2));
  323.  
  324.           }
  325.           break;
  326.               
  327.       }
  328.           
  329.       $this->stopThickness($thickness);
  330.           
  331.     }
  332.  
  333.   }
  334.  
  335.   public function arc(awColor $color, awPoint $center, $width, $height, $from, $to) {
  336.  
  337.     $this->resource,
  338.     $this->x + $center->x, $this->y + $center->y,
  339.     $width, $height,
  340.     $from, $to,
  341.     $this->getColor($color),
  342.     IMG_ARC_EDGED | IMG_ARC_NOFILL
  343.     );
  344.  
  345.   }
  346.  
  347.   public function filledArc(awColor $color, awPoint $center, $width, $height, $from, $to) {
  348.  
  349.     $this->resource,
  350.     $this->x + $center->x, $this->y + $center->y,
  351.     $width, $height,
  352.     $from, $to,
  353.     $this->getColor($color),
  354.     IMG_ARC_PIE
  355.     );
  356.  
  357.   }
  358.  
  359.   public function ellipse(awColor $color, awPoint $center, $width, $height) {
  360.  
  361.     list($x, $y) = $center->getLocation();
  362.  
  363.     $rgb = $this->getColor($color);
  364.     imageellipse(
  365.     $this->resource,
  366.     $this->x + $x,
  367.     $this->y + $y,
  368.     $width,
  369.     $height,
  370.     $rgb
  371.     );
  372.  
  373.   }
  374.  
  375.   public function filledEllipse($background, awPoint $center, $width, $height) {
  376.  
  377.     if($background instanceof awColor) {
  378.  
  379.       list($x, $y) = $center->getLocation();
  380.  
  381.       $rgb = $this->getColor($background);
  382.           
  383.       imagefilledellipse(
  384.       $this->resource,
  385.       $this->x + $x,
  386.       $this->y + $y,
  387.       $width,
  388.       $height,
  389.       $rgb
  390.       );
  391.           
  392.     } else if($background instanceof awGradient) {
  393.  
  394.       list($x, $y) = $center->getLocation();
  395.           
  396.       $x1 = $x - round($width / 2);
  397.       $y1 = $y - round($height / 2);
  398.       $x2 = $x1 + $width;
  399.       $y2 = $y1 + $height;
  400.  
  401.       $gradientDriver = new awGDGradientDriver($this);
  402.       $gradientDriver->filledEllipse(
  403.       $background,
  404.       $x1, $y1,
  405.       $x2, $y2
  406.       );
  407.  
  408.     }
  409.  
  410.   }
  411.  
  412.   public function rectangle(awColor $color, awLine $line) {
  413.  
  414.     list($p1, $p2) = $line->getLocation();
  415.  
  416.     switch($line->getStyle()) {
  417.  
  418.       case awLine::SOLID :
  419.         $thickness = $line->getThickness();
  420.         $this->startThickness($thickness);
  421.         $rgb = $this->getColor($color);
  422.         imagerectangle($this->resource, $this->x + $p1->x, $this->y + $p1->y, $this->x + $p2->x, $this->y + $p2->y, $rgb);
  423.         $this->stopThickness($thickness);
  424.         break;
  425.             
  426.       default :
  427.         /* <php5> */
  428.         $side = clone $line;
  429.         /* </php5> */
  430.  
  431.         /* <php4> --
  432.          $side = new Line($p1, $p2);
  433.          -- </php4> */
  434.  
  435.         // Top side
  436.         $side->setLocation(
  437.         new awPoint($p1->x, $p1->y),
  438.         new awPoint($p2->x, $p1->y)
  439.         );
  440.         $this->line($color, $side);
  441.  
  442.         // Right side
  443.         $side->setLocation(
  444.         new awPoint($p2->x, $p1->y),
  445.         new awPoint($p2->x, $p2->y)
  446.         );
  447.         $this->line($color, $side);
  448.  
  449.         // Bottom side
  450.         $side->setLocation(
  451.         new awPoint($p1->x, $p2->y),
  452.         new awPoint($p2->x, $p2->y)
  453.         );
  454.         $this->line($color, $side);
  455.  
  456.         // Left side
  457.         $side->setLocation(
  458.         new awPoint($p1->x, $p1->y),
  459.         new awPoint($p1->x, $p2->y)
  460.         );
  461.         $this->line($color, $side);
  462.             
  463.         break;
  464.  
  465.     }
  466.  
  467.   }
  468.  
  469.   public function filledRectangle($background, awLine $line) {
  470.  
  471.     $p1 = $line->p1;
  472.     $p2 = $line->p2;
  473.  
  474.     if($background instanceof awColor) {
  475.       $rgb = $this->getColor($background);
  476.       imagefilledrectangle($this->resource, $this->x + $p1->x, $this->y + $p1->y, $this->x + $p2->x, $this->y + $p2->y, $rgb);
  477.     } else if($background instanceof awGradient) {
  478.       $gradientDriver = new awGDGradientDriver($this);
  479.       $gradientDriver->filledRectangle($background, $p1, $p2);
  480.     }
  481.  
  482.   }
  483.  
  484.   public function polygon(awColor $color, awPolygon $polygon) {
  485.  
  486.     switch($polygon->getStyle()) {
  487.  
  488.       case awPolygon::SOLID :
  489.         $thickness = $polygon->getThickness();
  490.         $this->startThickness($thickness);
  491.         $points = $this->getPolygonPoints($polygon);
  492.         $rgb = $this->getColor($color);
  493.         imagepolygon($this->resource, $points, $polygon->count(), $rgb);
  494.         $this->stopThickness($thickness);
  495.         break;
  496.  
  497.       default :
  498.             
  499.         if($polygon->count() > 1) {
  500.  
  501.           $prev = $polygon->get(0);
  502.               
  503.           $line = new awLine;
  504.           $line->setStyle($polygon->getStyle());
  505.           $line->setThickness($polygon->getThickness());
  506.               
  507.           for($i = 1; $i < $polygon->count(); $i++) {
  508.             $current = $polygon->get($i);
  509.             $line->setLocation($prev, $current);
  510.             $this->line($color, $line);
  511.             $prev = $current;
  512.           }
  513.               
  514.           // Close the polygon
  515.           $line->setLocation($prev, $polygon->get(0));
  516.           $this->line($color, $line);
  517.               
  518.         }
  519.  
  520.     }
  521.  
  522.   }
  523.  
  524.   public function filledPolygon($background, awPolygon $polygon) {
  525.  
  526.     if($background instanceof awColor) {
  527.           
  528.       $points = $this->getPolygonPoints($polygon);
  529.       $rgb = $this->getColor($background);
  530.           
  531.       imagefilledpolygon($this->resource, $points, $polygon->count(), $rgb);
  532.           
  533.     } else if($background instanceof awGradient) {
  534.           
  535.       $gradientDriver = new awGDGradientDriver($this);
  536.       $gradientDriver->filledPolygon($background, $polygon);
  537.           
  538.     }
  539.  
  540.   }
  541.  
  542.   public function send(awImage $image) {
  543.  
  544.     $this->drawImage($image);
  545.  
  546.   }
  547.  
  548.   public function get(awImage $image) {
  549.  
  550.     return $this->drawImage($image, TRUE, FALSE);
  551.  
  552.   }
  553.  
  554.   public function getTextWidth(awText $text) {
  555.     $font = $text->getFont();
  556.  
  557.     if($font instanceof awPHPFont) {
  558.       $fontDriver = $this->phpFontDriver;
  559.     } else {
  560.       $fontDriver = $this->fileFontDriver;
  561.     }
  562.  
  563.     return $fontDriver->getTextWidth($text, $this);
  564.   }
  565.  
  566.   public function getTextHeight(awText $text) {
  567.     $font = $text->getFont();
  568.  
  569.     if($font instanceof awPHPFont) {
  570.       $fontDriver = $this->phpFontDriver;
  571.     } else {
  572.       $fontDriver = $this->fileFontDriver;
  573.     }
  574.  
  575.     return $fontDriver->getTextHeight($text, $this);
  576.   }
  577.  
  578.   protected function isCompatibleWithFont(awFont $font) {
  579.     if($font instanceof awFDBFont) {
  580.       return FALSE;
  581.     } else {
  582.       return TRUE;
  583.     }
  584.   }
  585.  
  586.   private function drawImage(awImage $image, $return = FALSE, $header = TRUE) {
  587.  
  588.     $format = $image->getFormatString();
  589.  
  590.     // Test if format is available
  591.     if((imagetypes() & $image->getFormat()) === FALSE) {
  592.       awImage::drawError("Class Image: Format '".$format."' is not available on your system. Check that your PHP has been compiled with the good libraries.");
  593.     }
  594.  
  595.     // Get some infos about this image
  596.     switch($format) {
  597.       case 'jpeg' :
  598.         $function = 'imagejpeg';
  599.         break;
  600.       case 'png' :
  601.         $function = 'imagepng';
  602.         break;
  603.       case 'gif' :
  604.         $function = 'imagegif';
  605.         break;
  606.     }
  607.  
  608.     // Send headers to the browser
  609.     if($header === TRUE) {
  610.       $image->sendHeaders();
  611.     }
  612.  
  613.     if($return) {
  614.       ob_start();
  615.     }
  616.  
  617.     $function($this->resource);
  618.  
  619.     if($return) {
  620.       return ob_get_clean();
  621.     }
  622.   }
  623.  
  624.   private function getPolygonPoints(awPolygon $polygon) {
  625.  
  626.     $points = array();
  627.  
  628.     foreach($polygon->all() as $point) {
  629.       $points[] = $point->x + $this->x;
  630.       $points[] = $point->y + $this->y;
  631.     }
  632.  
  633.     return $points;
  634.  
  635.   }
  636.  
  637.   private function startThickness($thickness) {
  638.  
  639.     if($thickness > 1) {
  640.  
  641.       // Beurk :'(
  642.       if($this->antiAliasing and function_exists('imageantialias')) {
  643.         imageantialias($this->resource, FALSE);
  644.       }
  645.       imagesetthickness($this->resource, $thickness);
  646.           
  647.     }
  648.  
  649.   }
  650.  
  651.   private function stopThickness($thickness) {
  652.  
  653.     if($thickness > 1) {
  654.  
  655.       if($this->antiAliasing and function_exists('imageantialias')) {
  656.         imageantialias($this->resource, TRUE);
  657.       }
  658.       imagesetthickness($this->resource, 1);
  659.           
  660.     }
  661.  
  662.   }
  663.  
  664.  
  665. }
  666.  
  667. registerClass('GDDriver');
  668.  
  669. /**
  670.  * To your gradients
  671.  *
  672.  * @package linea21.externals
  673.  * @subpackage artichow
  674.  */
  675.  
  676.  
  677.   /**
  678.    * A driver
  679.    *
  680.    * @var awGDDriver 
  681.    */
  682.   protected $driver;
  683.  
  684.   /**
  685.    * Build your GDGradientDriver
  686.    *
  687.    * @var awGDDriver $driver 
  688.    */
  689.   public function __construct(awGDDriver $driver) {
  690.  
  691.     $this->driver = $driver;
  692.  
  693.   }
  694.  
  695.   public function drawFilledFlatTriangle(awGradient $gradient, awPoint $a, awPoint $b, awPoint $c) {
  696.  
  697.     if($gradient->angle !== 0) {
  698.       awImage::drawError("Class GDGradientDriver: Flat triangles can only be used with 0 degree gradients.");
  699.     }
  700.  
  701.     // Look for right-angled triangle
  702.     if($a->x !== $b->x and $b->x !== $c->x) {
  703.       awImage::drawError("Class GDGradientDriver: Not right-angled flat triangles are not supported yet.");
  704.     }
  705.  
  706.     if($a->x === $b->x) {
  707.       $d = $a;
  708.       $e = $c;
  709.     } else {
  710.       $d = $c;
  711.       $e = $a;
  712.     }
  713.  
  714.     $this->init($gradient, $b->y - $d->y);
  715.  
  716.     for($i = $c->y + 1; $i < $b->y; $i++) {
  717.           
  718.       $color = $this->color($i - $d->y);
  719.       $pos = ($i - $d->y) / ($b->y - $d->y);
  720.           
  721.       $p1 = new awPoint($e->x, $i);
  722.       $p2 = new awPoint(1 + floor($e->x - $pos * ($e->x - $d->x)), $i);
  723.           
  724.       $this->driver->filledRectangle($color, new awLine($p1, $p2));
  725.           
  726.       unset($color);
  727.           
  728.     }
  729.  
  730.   }
  731.  
  732.   protected function drawFilledTriangle(awGradient $gradient, awPolygon $polygon) {
  733.  
  734.     if($gradient->angle === 0) {
  735.       $this->drawFilledTriangleVertically($gradient, $polygon);
  736.     } elseif($gradient->angle === 90) {
  737.       $this->drawFilledTriangleHorizontally($gradient, $polygon);
  738.     }
  739.  
  740.   }
  741.  
  742.   private function drawFilledTriangleVertically(awGradient $gradient, awPolygon $polygon) {
  743.     list($yMin, $yMax) = $polygon->getBoxYRange();
  744.  
  745.     $this->init($gradient, $yMax - $yMin);
  746.  
  747.     // Get the triangle line we will draw our lines from
  748.     $fromLine = NULL;
  749.     $lines = $polygon->getLines();
  750.  
  751.     $count = count($lines);
  752.         
  753.     // Pick the side of the triangle going from the top
  754.     // to the bottom of the surrounding box
  755.     for($i = 0; $i < $count; $i++) {
  756.       if($lines[$i]->isTopToBottom($polygon)) {
  757.         list($fromLine) = array_splice($lines, $i, 1);
  758.         break;
  759.       }
  760.     }
  761.  
  762.     // If for some reason the three points are aligned,
  763.     // $fromLine will still be NULL
  764.     if($fromLine === NULL) {
  765.       return;
  766.     }
  767.  
  768.     $fillLine = NULL;
  769.     for($y = round($yMin); $y < round($yMax); $y++) {
  770.           
  771.       $fromX = $fromLine->getXFrom($y);
  772.           
  773.       $toX = array();
  774.       foreach($lines as $line) {
  775.         $xValue = $line->getXFrom($y);
  776.  
  777.         if(!is_null($xValue)) {
  778.           $toX[] = $xValue;
  779.         }
  780.       }
  781.           
  782.       if(count($toX) === 1) {
  783.         $fillLine = new Line(
  784.         new Point($fromX, $y),
  785.         new Point($toX[0], $y)
  786.         );
  787.       } else {
  788.             
  789.         $line1 = new Line(
  790.         new Point($fromX, $y),
  791.         new Point($toX[0], $y)
  792.         );
  793.         $line2 = new  Line(
  794.         new Point($fromX, $y),
  795.         new Point($toX[1], $y)
  796.         );
  797.             
  798.         if($line1->getSize() < $line2->getSize()) {
  799.           $fillLine = $line1;
  800.         } else {
  801.           $fillLine = $line2;
  802.         }
  803.       }
  804.           
  805.       if(!$fillLine->isPoint()) {
  806.         $color = $this->color($y - $yMin);
  807.         $this->driver->line($color, $fillLine);
  808.  
  809.         unset($color);
  810.       }
  811.     }
  812.  
  813.   }
  814.  
  815.   private function drawFilledTriangleHorizontally(awGradient $gradient, awPolygon $polygon) {
  816.     list($xMin, $xMax) = $polygon->getBoxXRange();
  817.  
  818.     $this->init($gradient, $xMax - $xMin);
  819.  
  820.     // Get the triangle line we will draw our lines from
  821.     $fromLine = NULL;
  822.     $lines = $polygon->getLines();
  823.  
  824.     $count = count($lines);
  825.         
  826.     // Pick the side of the triangle going all the way
  827.     // from the left side to the right side of the surrounding box
  828.     for($i = 0; $i < $count; $i++) {
  829.       if($lines[$i]->isLeftToRight($polygon)) {
  830.         list($fromLine) = array_splice($lines, $i, 1);
  831.         break;
  832.       }
  833.     }
  834.  
  835.     // If for some reason the three points are aligned,
  836.     // $fromLine will still be NULL
  837.     if($fromLine === NULL) {
  838.       return;
  839.     }
  840.  
  841.     $fillLine = NULL;
  842.     for($x = round($xMin); $x < round($xMax); $x++) {
  843.           
  844.       $fromY = floor($fromLine->getYFrom($x));
  845.           
  846.       $toY = array();
  847.       foreach($lines as $line) {
  848.         $yValue = $line->getYFrom($x);
  849.  
  850.         if(!is_null($yValue)) {
  851.           $toY[] = floor($yValue);
  852.         }
  853.       }
  854.           
  855.       if(count($toY) === 1) {
  856.         $fillLine = new Line(
  857.         new Point($x, $fromY),
  858.         new Point($x, $toY[0])
  859.         );
  860.       } else {
  861.             
  862.         $line1 = new Line(
  863.         new Point($x, $fromY),
  864.         new Point($x, $toY[0])
  865.         );
  866.         $line2 = new  Line(
  867.         new Point($x, $fromY),
  868.         new Point($x, $toY[1])
  869.         );
  870.             
  871.         if($line1->getSize() < $line2->getSize()) {
  872.           $fillLine = $line1;
  873.         } else {
  874.           $fillLine = $line2;
  875.         }
  876.       }
  877.           
  878.       $color = $this->color($x - $xMin);
  879.       if($fillLine->isPoint()) {
  880.         $this->driver->point($color, $fillLine->p1);
  881.       } elseif($fillLine->getSize() >= 1) {
  882.         $this->driver->line($color, $fillLine);
  883.       }
  884.       unset($color);
  885.     }
  886.  
  887.   }
  888.  
  889.   public function filledRectangle(awGradient $gradient, awPoint $p1, awPoint $p2) {
  890.  
  891.     list($x1, $y1) = $p1->getLocation();
  892.     list($x2, $y2) = $p2->getLocation();
  893.  
  894.     if($y1 < $y2) {
  895.       $y1 ^= $y2 ^= $y1 ^= $y2;
  896.     }
  897.  
  898.     if($x2 < $x1) {
  899.       $x1 ^= $x2 ^= $x1 ^= $x2;
  900.     }
  901.  
  902.     if($gradient instanceof awLinearGradient) {
  903.       $this->rectangleLinearGradient($gradient, new awPoint($x1, $y1), new awPoint($x2, $y2));
  904.     } else {
  905.       awImage::drawError("Class GDGradientDriver: This gradient is not supported by rectangles.");
  906.     }
  907.  
  908.   }
  909.  
  910.   public function filledPolygon(awGradient $gradient, awPolygon $polygon) {
  911.  
  912.     if($gradient instanceof awLinearGradient) {
  913.       $this->polygonLinearGradient($gradient, $polygon);
  914.     } else {
  915.       awImage::drawError("Class GDGradientDriver: This gradient is not supported by polygons.");
  916.     }
  917.  
  918.   }
  919.  
  920.   protected function rectangleLinearGradient(awLinearGradient $gradient, awPoint $p1, awPoint $p2) {
  921.  
  922.     list($x1, $y1) = $p1->getLocation();
  923.     list($x2, $y2) = $p2->getLocation();
  924.  
  925.     if($y1 - $y2 > 0) {
  926.  
  927.       if($gradient->angle === 0) {
  928.             
  929.         $this->init($gradient, $y1 - $y2);
  930.  
  931.         for($i = $y2; $i <= $y1; $i++) {
  932.  
  933.           $color = $this->color($i - $y2);
  934.               
  935.           $p1 = new awPoint($x1, $i);
  936.           $p2 = new awPoint($x2, $i);
  937.               
  938.           $this->driver->filledRectangle($color, new awLine($p1, $p2));
  939.               
  940.           unset($color);
  941.               
  942.         }
  943.  
  944.       } else if($gradient->angle === 90) {
  945.             
  946.         $this->init($gradient, $x2 - $x1);
  947.  
  948.         for($i = $x1; $i <= $x2; $i++) {
  949.  
  950.           $color = $this->color($i - $x1);
  951.               
  952.           $p1 = new awPoint($i, $y2);
  953.           $p2 = new awPoint($i, $y1);
  954.               
  955.           $this->driver->filledRectangle($color, new awLine($p1, $p2));
  956.               
  957.           unset($color);
  958.               
  959.         }
  960.  
  961.       }
  962.           
  963.     }
  964.  
  965.   }
  966.  
  967.   public function filledEllipse(awGradient $gradient, $x1, $y1, $x2, $y2) {
  968.  
  969.     if($y1 < $y2) {
  970.       $y1 ^= $y2 ^= $y1 ^= $y2;
  971.     }
  972.  
  973.     if($x2 < $x1) {
  974.       $x1 ^= $x2 ^= $x1 ^= $x2;
  975.     }
  976.  
  977.     if($gradient instanceof awRadialGradient) {
  978.       $this->ellipseRadialGradient($gradient, $x1, $y1, $x2, $y2);
  979.     } else if($gradient instanceof awLinearGradient) {
  980.       $this->ellipseLinearGradient($gradient, $x1, $y1, $x2, $y2);
  981.     } else {
  982.       awImage::drawError("Class GDGradientDriver: This gradient is not supported by ellipses.");
  983.     }
  984.  
  985.   }
  986.  
  987.   protected function ellipseRadialGradient(awGradient $gradient, $x1, $y1, $x2, $y2) {
  988.  
  989.     if($y1 - $y2 > 0) {
  990.  
  991.       if($y1 - $y2 != $x2 - $x1) {
  992.         awImage::drawError("Class GDGradientDriver: Radial gradients are only implemented on circle, not ellipses.");
  993.       }
  994.           
  995.       $c = new awPoint($x1 + ($x2 - $x1) / 2, $y1 + ($y2 - $y1) / 2);
  996.       $r = ($x2 - $x1) / 2;
  997.       $ok = array();
  998.           
  999.       // Init gradient
  1000.       $this->init($gradient, $r);
  1001.           
  1002.       for($i = 0; $i <= $r; $i += 0.45) {
  1003.             
  1004.         $p = ceil((2 * M_PI * $i));
  1005.  
  1006.         if($p > 0) {
  1007.           $interval = 360 / $p;
  1008.         } else {
  1009.           $interval = 360;
  1010.         }
  1011.  
  1012.         $color = $this->color($i);
  1013.  
  1014.         for($j = 0; $j < 360; $j += $interval) {
  1015.  
  1016.           $rad = ($j / 360) * (2 * M_PI);
  1017.               
  1018.           $x = round($i * cos($rad));
  1019.           $y = round($i * sin($rad));
  1020.               
  1021.           $l = sqrt($x * $x + $y * $y);
  1022.               
  1023.           if($l <= $r) {
  1024.                 
  1025.             if(
  1026.             array_key_exists((int)$x, $ok) === FALSE or
  1027.             array_key_exists((int)$y, $ok[$x]) === FALSE
  1028.             ) {
  1029.  
  1030.               // Print the point
  1031.               $this->driver->point($color, new awPoint($c->x + $x, $c->y + $y));
  1032.                   
  1033.               $ok[(int)$x][(int)$y] = TRUE;
  1034.  
  1035.             }
  1036.  
  1037.           }
  1038.  
  1039.         }
  1040.  
  1041.         unset($color);
  1042.             
  1043.       }
  1044.  
  1045.     }
  1046.  
  1047.   }
  1048.  
  1049.   protected function ellipseLinearGradient(awGradient $gradient, $x1, $y1, $x2, $y2) {
  1050.  
  1051.     // Gauche->droite : 90°
  1052.  
  1053.     if($y1 - $y2 > 0) {
  1054.  
  1055.       if($y1 - $y2 != $x2 - $x1) {
  1056.         awImage::drawError("Class GDGradientDriver: Linear gradients are only implemented on circle, not ellipses.");
  1057.       }
  1058.           
  1059.       $r = ($x2 - $x1) / 2;
  1060.           
  1061.       // Init gradient
  1062.       $this->init($gradient, $x2 - $x1);
  1063.           
  1064.       for($i = -$r; $i <= $r; $i++) {
  1065.  
  1066.         $h = sin(acos($i / $r)) * $r;
  1067.  
  1068.         $color = $this->color($i + $r);
  1069.  
  1070.         if($gradient->angle === 90) {
  1071.  
  1072.           // Print the line
  1073.           $p1 = new awPoint(
  1074.           $x1 + $i + $r,
  1075.           round(max($y2 + $r - $h + 1, $y2))
  1076.           );
  1077.               
  1078.           $p2 = new awPoint(
  1079.           $x1 + $i + $r,
  1080.           round(min($y1 - $r + $h - 1, $y1))
  1081.           );
  1082.               
  1083.         } else {
  1084.  
  1085.           // Print the line
  1086.           $p1 = new awPoint(
  1087.           round(max($x1 + $r - $h + 1, $x1)),
  1088.           $y2 + $i + $r
  1089.           );
  1090.               
  1091.           $p2 = new awPoint(
  1092.           round(min($x2 - $r + $h - 1, $x2)),
  1093.           $y2 + $i + $r
  1094.           );
  1095.               
  1096.         }
  1097.  
  1098.         $this->driver->filledRectangle($color, new awLine($p1, $p2));
  1099.  
  1100.         unset($color);
  1101.             
  1102.       }
  1103.  
  1104.     }
  1105.  
  1106.   }
  1107.  
  1108.   protected function polygonLinearGradient(awLinearGradient $gradient, awPolygon $polygon) {
  1109.  
  1110.     $count = $polygon->count();
  1111.  
  1112.     if($count >= 4) {
  1113.  
  1114.       $left = $polygon->get(0);
  1115.       $right = $polygon->get($count - 1);
  1116.           
  1117.       if($gradient->angle === 0) {
  1118.             
  1119.         // Get polygon maximum and minimum
  1120.         $offset = $polygon->get(0);
  1121.         $max = $min = $offset->y;
  1122.         for($i = 1; $i < $count - 1; $i++) {
  1123.           $offset = $polygon->get($i);
  1124.           $max = max($max, $offset->y);
  1125.           $min = min($min, $offset->y);
  1126.         }
  1127.  
  1128.         $this->init($gradient, $max - $min);
  1129.             
  1130.         $prev = $polygon->get(1);
  1131.  
  1132.         $sum = 0;
  1133.             
  1134.         for($i = 2; $i < $count - 1; $i++) {
  1135.  
  1136.           $current = $polygon->get($i);
  1137.               
  1138.           $interval = 1;
  1139.               
  1140.           if($i !== $count - 2) {
  1141.             $current->x -= $interval;
  1142.           }
  1143.               
  1144.           if($current->x - $prev->x > 0) {
  1145.  
  1146.             // Draw rectangle
  1147.             $x1 = $prev->x;
  1148.             $x2 = $current->x;
  1149.             $y1 = max($prev->y, $current->y);
  1150.             $y2 = $left->y;
  1151.  
  1152.             $gradient = new awLinearGradient(
  1153.             $this->color($max - $min - ($y2 - $y1)),
  1154.             $this->color($max - $min),
  1155.             0
  1156.             );
  1157.  
  1158.             if($y1 > $y2) {
  1159.               $y2 = $y1;
  1160.             }
  1161.  
  1162.             $this->driver->filledRectangle(
  1163.             $gradient,
  1164.             awLine::build($x1, $y1, $x2, $y2)
  1165.             );
  1166.  
  1167.             $top = ($prev->y < $current->y) ? $current : $prev;
  1168.             $bottom = ($prev->y >= $current->y) ? $current : $prev;
  1169.  
  1170.             $gradient = new awLinearGradient(
  1171.             $this->color($bottom->y - $min),
  1172.             $this->color($max - $min - ($y2 - $y1)),
  1173.             0
  1174.             );
  1175.  
  1176.  
  1177.             $gradientDriver = new awGDGradientDriver($this->driver);
  1178.             $gradientDriver->drawFilledFlatTriangle(
  1179.             $gradient,
  1180.             new awPoint($prev->x, min($prev->y, $current->y)),
  1181.             $top,
  1182.             new awPoint($current->x, min($prev->y, $current->y))
  1183.             );
  1184.             unset($gradientDriver);
  1185.  
  1186.             $sum += $current->x - $prev->x;
  1187.  
  1188.           }
  1189.               
  1190.           $prev = $current;
  1191.           $prev->x += $interval;
  1192.  
  1193.         }
  1194.             
  1195.       } else if($gradient->angle === 90) {
  1196.  
  1197.         $width = $right->x - $left->x;
  1198.         $this->init($gradient, $width);
  1199.  
  1200.         $pos = 1;
  1201.         $next = $polygon->get($pos++);
  1202.  
  1203.         $this->next($polygon, $pos, $prev, $next);
  1204.             
  1205.         for($i = 0; $i <= $width; $i++) {
  1206.  
  1207.           $x = $left->x + $i;
  1208.               
  1209.           $y1 = round($prev->y + ($next->y - $prev->y) * (($i + $left->x - $prev->x) / ($next->x - $prev->x)));
  1210.           $y2 = $left->y;
  1211.  
  1212.           // Draw line
  1213.           $color = $this->color($i);
  1214.           // YaPB : PHP does not handle alpha on lines
  1215.           $this->driver->filledRectangle($color, awLine::build($x, $y1, $x, $y2));
  1216.  
  1217.           unset($color);
  1218.               
  1219.           // Jump to next point
  1220.           if($next->x == $i + $left->x) {
  1221.                 
  1222.             $this->next($polygon, $pos, $prev, $next);
  1223.  
  1224.           }
  1225.  
  1226.         }
  1227.  
  1228.       }
  1229.           
  1230.     } else if($count === 3) {
  1231.       $this->drawFilledTriangle(
  1232.       $gradient,
  1233.       $polygon
  1234.       );
  1235.     }
  1236.  
  1237.   }
  1238.  
  1239.   private function next($polygon, &$pos, &$prev, &$next) {
  1240.  
  1241.     do {
  1242.       $prev = $next;
  1243.       $next = $polygon->get($pos++);
  1244.     }
  1245.     while($next->x - $prev->x == 0 and $pos < $polygon->count());
  1246.  
  1247.   }
  1248.  
  1249.   /**
  1250.    * Start colors
  1251.    *
  1252.    * @var int 
  1253.    */
  1254.   private $r1, $g1, $b1, $a1;
  1255.  
  1256.   /**
  1257.    * Stop colors
  1258.    *
  1259.    * @var int 
  1260.    */
  1261.   private $r2, $g2, $b2, $a2;
  1262.  
  1263.   /**
  1264.    * Gradient size in pixels
  1265.    *
  1266.    * @var int 
  1267.    */
  1268.   private $size;
  1269.  
  1270.  
  1271.   private function init(awGradient $gradient, $size) {
  1272.  
  1273.     list(
  1274.     $this->r1, $this->g1, $this->b1, $this->a1
  1275.     ) = $gradient->from->rgba();
  1276.  
  1277.     list(
  1278.     $this->r2, $this->g2, $this->b2, $this->a2
  1279.     ) = $gradient->to->rgba();
  1280.  
  1281.     $this->size = $size;
  1282.   }
  1283.  
  1284.   private function color($pos) {
  1285.  
  1286.     return new awColor(
  1287.     $this->getRed($pos),
  1288.     $this->getGreen($pos),
  1289.     $this->getBlue($pos),
  1290.     $this->getAlpha($pos)
  1291.     );
  1292.  
  1293.   }
  1294.  
  1295.  
  1296.   private function getRed($pos) {
  1297.     if((float)$this->size !== 0.0) {
  1298.       return (int)round($this->r1 + ($pos / $this->size) * ($this->r2 - $this->r1));
  1299.     } else {
  1300.       return 0;
  1301.     }
  1302.   }
  1303.  
  1304.   private function getGreen($pos) {
  1305.     if((float)$this->size !== 0.0) {
  1306.       return (int)round($this->g1 + ($pos / $this->size) * ($this->g2 - $this->g1));
  1307.     } else {
  1308.       return 0;
  1309.     }
  1310.   }
  1311.  
  1312.   private function getBlue($pos) {
  1313.     if((float)$this->size !== 0.0) {
  1314.       return (int)round($this->b1 + ($pos / $this->size) * ($this->b2 - $this->b1));
  1315.     } else {
  1316.       return 0;
  1317.     }
  1318.   }
  1319.  
  1320.   private function getAlpha($pos) {
  1321.     if((float)$this->size !== 0.0) {
  1322.       return (int)round(($this->a1 + ($pos / $this->size) * ($this->a2 - $this->a1)) / 127 * 100);
  1323.     } else {
  1324.       return 0;
  1325.     }
  1326.   }
  1327.  
  1328. }
  1329.  
  1330. registerClass('GDGradientDriver');
  1331.  
  1332. /*
  1333.  * Check for GD2
  1334.  */
  1335. if(function_exists('imagecreatetruecolor') === FALSE) {
  1336.   awImage::drawErrorFile('missing-gd2');
  1337. }
  1338.  
  1339. ?>

Documentation generated on Fri, 01 Apr 2011 09:31:05 +0200 by phpDocumentor 1.4.1