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

Documentation generated on Thu, 03 May 2012 15:04:47 +0200 by phpDocumentor 1.4.1