在Firefox中破碎的GD库Pngs

时间:2012-09-17 15:49:09

标签: php gd

我使用PHP和GD库创建了自己的自定义蜘蛛图生成器。基本上,用户回答一系列问题,并根据问题的答案生成蜘蛛图表。

总的来说,一切都很好。生成的图表在数学上是准确的(但是,测验需要完全重写),并且它似乎足够快。但是,我注意到的是,当我尝试从Firefox(Snowleopard上的15.0.1版本)保存图像时,图像本身无法打开。从任何其他浏览器保存图像会产生可在任何图像编辑器中打开的工作图像。

我觉得特别有趣的是它什么时候打破了。我会看看能否准确解释这一点。

完整的工作版本是[不再在这里],这里是处理和生成图表本身所涉及的所有相关代码位:

chart.php (处理POST数据)     

$r = 300; //Radius
//Processing of information passed from the previous form yields an array $cargs
//$cargs contains key value pairs. Values are of type float with a range 0-$r

$chart = new Chart($r); //Generates Canvas and Circle
$chart->generate($cargs); //Generates Polygon based on $cargs

header("Content-type: image/png");
imagesavealpha($chart->image, true);
imagepng($chart->image);
imagedestroy($chart->image);
?>

SS_Chart.php (图表对象)

class Chart
{
    public $radius;
    public $diameter;
    public $image;

    private $_labels;
    private $_values;
    private $_n;

    public function Chart($r=300)
    {
        $this->radius = $r;
        $this->diameter = 2*$r;
        $this->image = $this->_get_transparent_canvas($this->diameter, $this->diameter);
        $this->_draw_circle();
    }
    public function generate($arr)
    {
        if(count($arr)>2)
        {
            $red = imagecolorallocate($this->image, 255, 0, 0);
            $this->_n = count($arr);
            $this->_labels = array_keys($arr);
            $this->_values = array_values($arr);

            $coors = array();
            for($i=0;$i<$this->_n;$i++)
            {
                //Generate coordinates....
            }
            imagefilledpolygon($this->image, $coors, $this->_n, $red);
        }
        else
            trigger_error('Number of $key=>$value pairs in arguments must be 3 or greater', E_USER_ERROR);
    }
    private function _get_transparent_canvas($w, $h)
    {
        $canvas = imagecreatetruecolor($w, $h);
        imagealphablending($canvas, true);
        $transparent = imagecolorallocatealpha($canvas, 0, 0, 0, 127);
        imagefill($canvas, 0, 0, $transparent);

        return $canvas;
    }
    private function _draw_circle()
    {
        $white = imagecolorallocate($this->image, 255, 255, 255);
        imagearc($this->image, $this->radius, $this->radius, $this->diameter, $this->diameter,  0, 360, $white);
    }
}

以下是有趣的地方:在chart.php中评论$chart->generate($cargs);时,Firefox会根据尺寸以及白色圆圈生成可工作且可编辑的透明png。

但是,如果我在SS_Chart.php中注释public function generate内的所有内容并且$chart->generate($cargs);取消注释(基本上导致一个运行的方法,但实际上没有做任何事情),那么生成的png可以不再被打开。

怎么可能?

除了奇怪的论坛之外,我还没有找到太多关于这个问题的文章,描述了使用GD库让Firefox进入jive的一些困难,但这是我第一次遇到这样的事情。

  • 如果我的代码出现问题,那么问题不会在所有浏览器中普遍存在吗?
  • 这是否与范围更有关,以及主要GD功能是否在对象中使用这一事实?
  • 此外,这个问题是否会发生在其他人身上?
  • 以前是否有人遇到这样的问题?
  • 这甚至是已知的问题吗?

这实际上更多是一种好奇心,而不是一个真正的“问题”,但对此事的任何见解都将非常感激。

2 个答案:

答案 0 :(得分:2)

查看 SAVED 图片的来源

<br />
<b>Fatal error</b>:  Number of $key=>$value pairs in arguments must be 3 or greater in <b>/home/mattmaio/public_html/dev/assets/classes/SS_Chart.php</b> on line <b>38</b><br />

当您将其保存在Firefox中时,fireox不会保存您所看到的内容。它的作用是 - 它在保存时发出另一个GET请求。

GET http://dev.mattmaiorano.com/chart.php HTTP/1.1
Host: dev.mattmaiorano.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://dev.mattmaiorano.com/chart.php

显然,所有POST数据都会丢失,因此会出错。我不确定你的评论是什么,但我想这就是它。

答案 1 :(得分:1)

我在这里看到2个

  • 保存
  • Broken Circle

保存

您应该做的是保存图像,然后使用readfile输出文件,这样就不需要重新生成文件了,而且它可以在Firefox上运行

  

不必始终生成图像也有助于保留带宽

示例代码

$r = 300; // $cargs
$tempDir = "xxx";
session_start();

__flush($tempDir);

if (isset($_POST) || ! isset($_SESSION['file'])) {
    $_SESSION['file'] = $tempDir . DIRECTORY_SEPARATOR . sha1(serialize($_POST)) . ".png";
}

header("Content-type: image/png");
$file = $_SESSION['file'];

if (file_exists($file)) {
    readfile($file);
} else {
    $chart = new Chart($r); // Generates Canvas and Circle
    $chart->generate(array("A" => array(40,50),"B" => array(20,240),"C" => array(60,60),"D" => array(240,20),"E" => array(50,40),"F" => array(10,10))); // Generates

    imagesavealpha($chart->image, true);
    imagepng($chart->image, $file);
    imagedestroy($chart->image);
}

破碎圈

破碎的圈子has nothing to do with Firefox ..在我初步调查中,当我使用自己的变量运行代码时,它会生成以下图像..

enter image description here

问题

从上面的图片green制作者显示了破碎的圆圈。当以下情况属实时,我发现这个错误:

  

画布宽度=圆直径

您正在调用的代码形式如下:

imagearc($this->image, $this->radius, $this->radius, $this->diameter, $this->diameter, 0, 360, $white);

解决方案

你应该做的是用这样的东西减少圆的直径

  imagearc($this->image, $this->radius, $this->radius, ceil(0.9 * $this->diameter), ceil(0.9 * $this->diameter), 0, 360, $white);

你会得到一个完美的圆圈

enter image description here

使用的代码

$r = 300; // $cargs
$tempDir = "xxx";
session_start();

__flush($tempDir);

if (isset($_POST) || ! isset($_SESSION['file'])) {
    $_SESSION['file'] = $tempDir . DIRECTORY_SEPARATOR . sha1(serialize($_POST)) . ".png";
}

header("Content-type: image/png");
$file = $_SESSION['file'];

if (file_exists($file)) {
    readfile($file);
} else {
    $chart = new Chart($r); // Generates Canvas and Circle
    $chart->generate(array("A" => array(40,50),"B" => array(20,240),"C" => array(60,60),"D" => array(240,20),"E" => array(50,40),"F" => array(10,10))); // Generates

    imagesavealpha($chart->image, true);
    imagepng($chart->image, $file);
    imagedestroy($chart->image);
}

function __flush($tempDir) {
    $expire = 300; // 5mins
    $iterator = new DirectoryIterator($tempDir);
    foreach ( $iterator as $fileinfo ) {

        if ($fileinfo->isDot())
            continue;

        if ((time() - $fileinfo->getMTime()) > $expire) {
            @unlink($iterator->getPath());
        }
    }
}


class Chart {
    public $radius;
    public $diameter;
    public $image;
    private $_labels;
    private $_values;
    private $_n;

    public function Chart($r = 300) {
        $this->radius = $r;
        $this->diameter = 2 * $r;
        $this->image = $this->_get_transparent_canvas($this->diameter, $this->diameter);
        $this->_draw_circle();
    }

    public function generate($arr) {
        if (count($arr) > 2) {
            $red = imagecolorallocate($this->image, 255, 0, 0);
            $this->_n = count($arr);
            $this->_labels = array_keys($arr);
            $this->_values = array_values($arr);

            $coors = array();
            foreach ( $this->_values as $key => $value ) {
                $coors = array_merge($coors, $value);
            }
            imagefilledpolygon($this->image, $coors, $this->_n, $red);
        } else
            trigger_error('Number of $key=>$value pairs in arguments must be 3 or greater', E_USER_ERROR);
    }

    private function _get_transparent_canvas($w, $h) {
        $canvas = imagecreatetruecolor($w, $h);
        imagealphablending($canvas, true);
        $transparent = imagecolorallocatealpha($canvas, 0, 0, 0, 127);
        imagefill($canvas, 0, 0, $transparent);

        return $canvas;
    }

    private function _draw_circle() {
        $white = imagecolorallocate($this->image, 255, 255, 255);
        imagearc($this->image, $this->radius, $this->radius, ceil(0.9 * $this->diameter), ceil(0.9 * $this->diameter), 0, 360, $white);
        // imagearc($this->image, $this->radius, $this->radius,
    // $this->diameterCycle, $this->diameterCycle, 0, 360, $white);
    }
}