Plist解析(拆分大图为小图)的核心算法讲解。

注意,这是核心算法讲解文章,

主文请移步:开源一个基于Unity的Plist解析工具——TextureUnpacker

 

一、从plist中筛选出有用的信息

    1、Metadata(Plist信息): format(plist类型)、textureFileName(大图名称)、size(大图大小)。

    2、Frame(小图信息): textureName(小图名称)、startPos(小图在大图中的起始位置(左上角-左上角))、size(小图大小)、sourceSize(小图裁剪前的原大小)、isRotated(小图在大图中是否经过了旋转)、offset(小图裁剪前后中心点的偏移值)。

    注意: 在不同的plist中字段的名称可能不同,但要表达的含义是相同的。

二、分析数据

通过对plist的数据和大图进行比对和分析,可以发现:

    1、size(小图大小)、sourceSize(小图裁剪前的原大小),都是小图未旋转前的宽高

    2、startPos(小图在大图中的起始位置), 以“向下”为Y轴正方向

    3、offset(小图裁剪前后中心点的偏移值),以“向上”为Y轴正方向

其中,第3条的分析过程如下:

    选用format为2的plist,因为此类型的plist中,小图的 “sourceColorRect” 字段,标明了裁剪后的小图在原小图上的起始位置(左上角-左上角),这里且称它为 trimStartPos。trimStartPos可以和offset(小图裁剪前后中心点的偏移值)进行相互推导。如下图:

Plist解析(拆分大图为小图)的核心算法讲解。_第1张图片

    将小图的数据(format为2的plist(数据充分),且未经过旋转的小图(避免干扰))代入,即可判断出offset的Y轴方向与startPos(小图在大图中的起始位置)的方向相反,即,以“向上”为Y轴正方向

    在此基础上,代入旋转了的小图数据,发现其依然满足 trimStartPos 与 offset的推导关系,由此可得出结论:裁剪与旋转与否无关,即:Texturepacker在合成大图时,其步骤为:先裁剪(得出offset);再旋转(宽高调换);最后拼入大图(得到小图在大图中的位置startPos)。

三、拆分大图为小图

    仅拆分大图为小图,不需要考虑offset,逻辑非常简单。

    思路: 创建一张与小图大小相同的目标图,然后根据 startPos(小图在大图中的起始位置(左上角-左上角))、size(小图大小)得到采样区,最后,将采样区对应像素逐一赋值给目标图。

    首先,需要重新计算 startPos,因为原startPos是以大图左上为起点,向下为正方向的;而将要使用的采集像素方法 GetPixels() 需要以大图左下为起点,以向上为正方向

    变换:保持startPos的x坐标不变,新的y坐标:大图高度-(startPos.y + 采样高度)

    (1)、未旋转小图的拆分

    目标图中的坐标(w, h),对应的采样区坐标为(w, h),直接逐一赋值即可。

    (2)、旋转小图的拆分

    采样宽高发生调换;

    目标图中的坐标(w, h),对应的采样区坐标为(h, sampleHeight -1- w ),即顺时针旋转90度。这里减一,是因为其高度范围实际为(0~sampleHeight-1),如下图:

    Plist解析(拆分大图为小图)的核心算法讲解。_第2张图片

四、将拆分的小图还原为原大小

    与拆分不同的是,还原小图要用到offset(还原的过程,就是把当初合图时,Trim掉的四周的透明像素加回去)。不过这个offset不能直接使用,因为它是小图中心点的偏移值,而实际需要的是裁剪前后“左下角-左下角”的偏移值。换算过程如下,注意两次因Y坐标轴相反而取反(对n取反,对DH向量的Y分量整体取反)

Plist解析(拆分大图为小图)的核心算法讲解。_第3张图片           

    (1)、未旋转小图的还原

    目标图中的坐标(w, h),对应的采样区坐标为(w-offsetLX, h-ofsetTY),逐一赋值即可。

    (2)、旋转小图的还原

     这种情况虽然比较复杂,但好在我们已经在 第二节 中得知 “合图顺序为先裁剪,后旋转”

     因为是求 目标图(等同原始图)中的坐标与采样区坐标的对应关系,就相当于将原始图执行一次正序的合图坐标变换,因此,按照这个顺序,先裁剪,得:

    w => w-offsetLX;    h => h-offsetBY;

再旋转(套用 三(2) 中的旋转)得:

    w => h-offsetBY;    w => sampleHeight-1-(w-offsetLX)

即,目标图中的坐标(w, h),对应的采样区坐标为(h-offsetBY, sampleHeight-1-(w-offsetLX))。

    按此对应坐标对目标图进行赋值就OK了。

你可能感兴趣的:(我的开源工具)