【问题标题】:Decompressing Tiled TMX file contents with PHP使用 PHP 解压 Tiled TMX 文件内容
【发布时间】:2012-05-16 07:36:56
【问题描述】:

我在从 .tmx(平铺)文件中提取图层内容时遇到问题。 我想在 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 方法之前裁剪我们的标题。

现在我的问题是:我必须先剪掉标题吗?如果是,我该怎么做? 如果没有,那我怎样才能得到未压缩的数据呢?

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

【问题讨论】:

标签: php xml gzip base64


【解决方案1】:

如前所述,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

希望对您有所帮助。

【讨论】:

  • 非常感谢!刚刚试了一下,它按说明工作。
【解决方案2】:

哇,这些 PHP 函数的名字太可怕了。先介绍一下背景。

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

  • 原始 deflate,即在 RFC 1951 中定义的压缩成没有标题或尾部的 deflate 格式的数据。
  • zlib,它是包装在一个紧凑的 zlib 标头和尾标中的原始 deflate 数据,其中包含一个两字节标头和一个四字节 Adler-32 校验值作为尾标,在 RFC 1950 中定义。
  • gzip,它是包装在 gzip 标头和预告片中的原始 deflate 数据,其中标头至少为 10 个字节,并且可以更长,包含文件名、cmets 和/或额外字段,以及 8 个字节的预告片带有一个四字节的 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 library 的一部分。)

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

【讨论】:

  • 遗憾的是,我只安装了 PHP 5.3.1 - 该版本中既不存在 zlib_encode() 也不存在 zlib_decode()。也没有找到我可以尝试的任何其他实现。但是您的回答确实帮助我理解了不同方法之间的所有差异,非常感谢!
  • 是的,只有 zlib_* 函数不存在
  • 没有一个 - 那是我的问题,不知何故,甚至 base64decode 都不起作用:(
【解决方案3】:

我知道这已经过时了,但我确实花了一整天的时间来处理这段代码。
我做的事情真的很挑剔。但是,这里有一个快速函数可以将 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
        )

)

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

【讨论】:

猜你喜欢
  • 2016-01-24
  • 2015-08-10
  • 2014-06-11
  • 2015-12-01
  • 2011-07-04
  • 1970-01-01
  • 2012-08-05
  • 1970-01-01
  • 2011-01-28
相关资源
最近更新 更多