使用PHP解压缩Tiled TMX文件内容

时间:2012-05-16 07:36:57

标签: php xml gzip base64

我在从.tmx(Tiled)文件中提取图层内容时遇到问题。 我希望在PHP中获得完整的未压缩数据,并对其进行一些描述。 获取宽度,高度等标题信息是没有问题的 - SimpleXML正在那里完成它的工作。但不知何故,瓦片层的解压缩无法正常工作。

数据本身存储为base64和gzip编码的字符串(类似于H4sIAAAAAAAAC+3bORKAIBQEUVzuf2YTTSwEA/gL00EnJvJQsAjcSyk7EU3v+Jn3OI)但是我甚至在获取base64解码的代码时遇到了问题(它只是给了我很奇怪的字符,当我在平铺中重新打开地图时并将其保存为“base64 uncompressed”,结果只是一个空字符串 - not 当然使用gzip解压缩。)

我已经在网上搜索了一下,看看数据是如何精确压缩的(Github article)。好像我必须使用gzinflate()命令而不是所有其他命令(例如gzuncompress),但这对我来说也不起作用。

我现在的代码如下:

<?php
  // Get the raw xml data
  $map_xml = new SimpleXML(file_get_contents("map.tmx"));
  $data = $map_xml["layer"][0]["data"]["@content"]; // I would make a loop here
  $content =gzinflate(base64_decode($map_content)); // gives me and error

  var_dump($data); // results in nothing
?>

经过一些研究后,我发现我应该使用zlib过滤器(php.net article)。 现在我真的很困惑我不知道应该选择什么 - 我再次询问谷歌并得到以下内容:Compressing with Java Decompressing with PHP。根据答案,我必须在使用base64和gzip方法之前裁剪标题。

现在我的问题:我之前是否需要裁剪标题?如果是的话,我该怎么做?  如果没有,那我怎么才能得到未压缩的数据?

我真的希望有人可以帮助我!

3 个答案:

答案 0 :(得分:4)

如前所述,Php的gzinflate和gzuncompress错误地命名。但是,我们可以利用接受原始压缩数据的gzinflate。 gzip头是10个字节长,可以使用substr去掉。使用上面的示例我尝试了这个:

$base64content = "H4sIAAAAAAAAC+3bORKAIBQEUVzuf2YTTSwEA/gL00EnJvJQsAjcSyk7EU3v+Jn3OI";
$compressed = substr( base64_decode($base64content), 10);
$content = gzinflate($compressed);

这为您提供了一个表示原始数据的字符串。你的TMX层主要由gid 0,2和3组成,因此如果打印出来,你只会看到空格。要获得有用的数据,您需要调用角色ord:

$chars = str_split($content);
$values = array();
foreach($chars as $char) {
    $values[] = ord($char);
}
var_dump( implode(',', $values) );  // This gives you the equivalent of saving your TMX file with tile data stored as csv

希望有所帮助。

答案 1 :(得分:2)

哇,这些PHP函数的命名非常可怕。有些背景知识。

您可能会遇到或能够制作三种格式。他们是:

  • 原始deflate,即压缩为deflate格式且没有标题或预告片的数据,在RFC 1951中定义。
  • zlib,它是一个包含在紧凑的zlib头和尾部中的原始deflate数据,它包含一个双字节头和一个四字节Adler-32检查值作为预告片,在RFC 1950中定义。
  • gzip,它是包含在gzip头文件和预告片中的原始deflate数据,其中头部至少为10个字节,并且可以更长,包含文件名,注释和/或额外字段,以及8字节预告片使用四字节CRC-32和未压缩长度模块2 ^ 32。这个包装器在RFC 1952中定义。这是您在具有后缀.gz
  • 的文件中找到的数据

PHP函数gzdeflate()gzinflate()创建并解码原始deflate格式。 PHP函数gzcompress()gzuncompress()创建并解码zlib格式。这些函数的名称中应该包含“gz”,因为它们的 none 处理gzip格式!对于试图创建或解码gzip格式数据的PHP编码器来说,这将永远令人困惑。

似乎(但文档不清楚,如果它们总是在那里)PHP函数gzencode()gzdecode(),如果我正确阅读简洁文档,默认情况下创建和解码gzip格式。 gzencode()还可以选择生成zlib格式,我怀疑gzdecode()会尝试自动检测gzip或zlib格式并进行相应的解码。 (这是所有这些函数都使用的实际zlib library的一部分功能。)

zlib_encode()zlib_decode()的文档不完整(这些页面承认:“此函数目前未记录;只有其参数列表可用”),因此很难说出它们是什么做。 encoding有一个未记录的zlib_encode()字符串参数,如果您知道要在字符串中放入什么,可能会允许您选择三种格式中的一种。 encoding没有zlib_decode()参数,因此可能尝试在三种格式中自动检测。

答案 2 :(得分:1)

我知道现在已经老了,但我真的花了一整天玩这段代码。
对我的所作所为非常挑剔。但是,这是一个快速功能,可以将TMX文件转换为每个图层上每个图块的ID数组。

其他答复的人会去帮助我在错误的地方拼凑起来。

<?php

function getLayer($getLayerName = '')
{
    $xml = simplexml_load_file('level.tmx');
    $values = array();
    foreach($xml->layer as $child)
    {
        $name = $child->attributes()->name;

        if(!empty($getLayerName))
            if($name != $getLayerName)
                continue;

        $data = gzinflate(substr(base64_decode(trim($child->data)), 10));
        $chars = str_split($data);
        $i = 0;
        foreach($chars as $char)
        {
            $charID = ord($char);
            if($i % 4 == 0) // I'm only interested in the tile IDs
            {
                $values[(String) $name][] = $charID;
            }
            $i++;
        }
    }
    return $values;
}

print_r(getLayer());
//or you could use getLayer('LayerName') to get a single layer!

?>

在我的示例3x3地图上,只有一个平铺图像,我得到以下内容:

Array
(
    [floor] => Array
        (
            [0] => 1
            [1] => 1
            [2] => 1
            [3] => 1
            [4] => 1
            [5] => 1
            [6] => 1
            [7] => 1
            [8] => 1
        )

    [layer2] => Array
        (
            [0] => 0
            [1] => 0
            [2] => 1
            [3] => 0
            [4] => 1
            [5] => 0
            [6] => 1
            [7] => 1
            [8] => 0
        )

)

希望这个功能对于那些需要它的人来说非常方便。