使用 PHP 解压缩平铺的 TMX 文件内容


Decompressing Tiled TMX file contents with PHP

我在从 .tmx(平铺(文件中提取图层内容时遇到问题。我想在PHP中获取完整的未压缩数据并对其进行一些图像。获取宽度,高度等标头信息是没有问题的 - SimpleXML正在那里做它的工作。但是不知何故,切片图层的解压缩不起作用。

数据本身存储为 base64 和 gzip 编码字符串(

sth 像 H4sIAAAAAAAAC+3bORKAIBQEUVzuf2YTTSwEA/gL00EnJvJQsAjcSyk7EU3v+Jn3OI 一样(,但我甚至无法获取 base64 解码代码(它只是给了我奇怪的字符,当我重新打开平铺地图并将其保存为"base64 未压缩"时,结果只是一个空字符串 - 当然不使用 gzip 解压缩(。

我已经在网上搜索并看到了数据是如何精确压缩的(Github文章(。似乎我必须使用 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 文章(。现在我真的很困惑,我不知道我应该选择什么 - 我再次问谷歌,得到以下结果:使用 Java 压缩 用 PHP 解压缩。根据答案,我必须在使用 base64 和 gzip 方法之前裁剪我们的标题。

现在我的问题:我必须先裁剪标题吗?如果是,我该怎么做? 如果没有,那么我如何获取未压缩的数据?

真的希望有人能在这里帮助我!

如前所述,Php 的 gzinflate 和 gzuncompress 被错误地命名。 但是,我们可以利用接受原始压缩数据的gzinfflat。 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

希望有帮助。

哇,这些PHP函数的名字很糟糕。 首先介绍一些背景。

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

  • 原始压缩,即压缩为 deflate 格式的数据,没有标头或尾部,在 RFC 1951 中定义。
  • zlib,
  • 它是包装在紧凑的 zlib 标头和尾部中的原始放气数据,它由一个两字节头和一个四字节 Adler-32 校验值组成,作为尾部,在 RFC 1950 中定义。
  • gzip,它是包装在 gzip 标头和尾部中的原始压缩数据,其中标头至少为 10 个字节,可以更长,包含文件名、注释和/或额外字段,以及一个带有四字节 CRC-32 和未压缩长度模块 2^32 的八字节尾部。 此包装器在 RFC 1952 中定义。 这是您将在带有后缀的文件中找到的数据 .gz .

PHP 函数gzdeflate()gzinflate()创建和解码原始 deflate 格式。 PHP 函数gzcompress()gzuncompress()创建和解码 zlib 格式。 这些函数的名称中不应该有"gz",因为它们都不处理 gzip 格式! 这将永远让试图创建或解码gzip格式数据的PHP编码人员感到困惑。

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

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

我知道这现在已经很旧了,但我真的花了一整天的时间玩这个代码。
我对自己的工作真的很挑剔。但是,这里有一个快速函数,可将 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
        )
)

希望此功能对于任何需要它的人来说都很方便。