WWW.lllT.neT这篇文章内容就来从零教你应用node笔写一款标准图集封装工具,有一定的实用价值,期待对各位有些协助!

偶然发现一款非常好用的混合开发图象编解码库node-images.

认真阅读其API, 就萌发了一个应用其制做小精灵标准图集的念头.

因此就兴起了这一专用工具sprites-pack-tool.

你能在github查询

https://github.com/xdq1553/MySpritesPackTool

你能应用npm安装

https://www.npmjs.com/package/sprites-pack-tool


针对小精灵标准图集, 我觉得大伙儿都不会生疏.

例如把接下来的多张相片合成一张.

1.png

2.png

这一张标准图集便是我用文中详细介绍的专用工具装包生成的.

生成的照片质量仍然十分高呢.

为何必须应用标准图集

web开发

我们在web开发中, 每回在电脑浏览器展现一张图片都必须post请求一次服务器空间.

举个事例, 3次post请求每回4k, 和一次post请求12k或是有不同之处的, 随后大量的情况下一次post请求并并不是3 * 4k.

应用标准图集能使我们提升网络资源载入, 提升网址的特性.

游戏软件开发

在游戏软件开发中, 标准图集的应用尤为重要, 无论是一般帧动画或是svga等动漫解决方法, 都不容易每份照片去post请求网络资源.

大量的情况下, 我们是装包成标准图集, 而标准图集封装工具texturepacker也是盛行.

次之, 动画场景太多, 大家一般都必须分阶段载入网络资源, 有的情况下一个动漫实体模型, 涉及到的照片少则十来张, 更多就是近百张.

标准图集的应用必不可少.

下边咱们就看来下怎样撰写一款标准图集封装工具.

专用工具设计方案

开发设计一个标准图集封装工具脚本制作需要什么招式.

  • node.js程序编写工作能力

  • 二维矩形框装车优化算法

随后大家思索如何去装包一张标准图集.

  • 大家必须寻找必须装包的文件夹名称, 很有可能有好几个或是嵌入文件夹名称.

  • 标准图集是好几张散图拼接而成.

  • 标准图集的尺寸必须可配备

  • 尽量的缩小标准图集室内空间, 使每份图密切迎合

  • 每一个文件夹名称装包成一个标准图集, 必须考虑到照片太多的状况

  • 很有可能必须转化成标准图集所须要的json文档, 纪录照片位置信息

逐渐撰写脚本制作

脚本制作IO

我这里是那样设计方案.

最先大家必须一个装包目标案例MySpritePackTool, 与此同时适用载入配备主要参数options.

/** 标准图集装包目标 */
const MySpritePackTool = function (opt) {
    this.options = {
        //一个文件夹图片太多或是太长 递归较大频次
        maxCount: opt.maxCount || 2,
        //必须装包标准图集的文件路径
        assetsPath: opt.assetsPath,
        //导出文件路径
        outPutPath: opt.outPutPath,
        //一张标准图集装包最大size
        maxSize: { width: 2048, height: 2048 }
    }
};

随后大家必须导出这一目标, 可以被别的工程所引入.

module.exports = MySpritePackTool;

解析xml文档转化成连接点树

大家的键入主要参数尽量的少, 那样就要大家程序流程去解析xml文件夹名称.

比如, 大家有如下所示的文件目录树:

|--assets
   |--index
      |--img-3.png
      |--img-4.png
   |--login
      |--img-5.png
   |--img-1.png
   |--img-2.png

大家必须每一个文件夹名称下装包出一张标准图集.

思索: 必须怎样的算法设计?

最先有利于js分析, 大家承诺一个目标,

每一层, 必须一个图片器皿assets;

一个所包括的照片标志keys;

一个文件夹名称名称, 也便捷大家后边为标准图集取名name;

随后各层文件夹名称前套同样目标;

构造如下所示:

{
  assets: [
    {
      id: 'assets/img-1.png',
      width: 190,
      height: 187
    },
    ...
  ],
  name: 'assets',
  keys: 'img-1.png,img-2.png,',
  index: {
    assets: [
        {
            id: 'assets/index/img-3.png',
            width: 190,
            height: 187
        },
        ...
    ],
    name: 'index',
    keys: 'img-3.png,img-4.png,'
  },
  login: {
    assets: [
        {
            id: 'assets/login/img-5.png',
            width: 190,
            height: 187
        }
    ],
    name: 'index',
    keys: 'img-5.png,'
  },
}

不会太难发觉, 大家早已可以获得必须装包的任何文档和文件夹名称.

那样用程序流程怎样完成呢?

关键使用nodejs的fs控制模块来递归实际操作文件夹名称, 并导出所须要的连接点树.

留意在撰写的过程中必须分辨是照片或是文件夹名称.

MySpritePackTool.prototype.findAllFiles = function (obj, rootPath) {
    let nodeFiles = [];
    if (fs.existsSync(rootPath)) {
        //获得全部文件夹名称
        nodeFiles = fs.readdirSync(rootPath);

        //拼装目标
        let nameArr = rootPath.split('/');
        obj["assets"] = [];
        obj["name"] = nameArr[nameArr.length - 1];
        obj["keys"] = "";

        nodeFiles.forEach(item => {
            //分辨并不是照片途径
            if (!/(.png)|(.jpe?g)$/.test(item)) {
                let newPath = path.join(rootPath, item);
                //分辨存有文档 与此同时是文件夹名称系统软件
                if (fs.existsSync(newPath) && fs.statSync(newPath).isDirectory()) {
                    // console.log("得到新的详细地址", newPath);
                    obj[item] = {};
                    this.findAllFiles(obj[item], newPath);

                } else {
                    console.log(`文件路径: ${newPath}未找到!`);
                }

            } else {
                console.log(`照片途径: ${item}`);
                obj["keys"]  = item   ",";
                let params = {};               params["id"] = path.resolve(rootPath, `./${item}`);
                //得到照片高宽
                params["width"] = images(path.resolve(rootPath, `./${item}`)).width();
                params["height"] = images(path.resolve(rootPath, `./${item}`)).height();
                obj["assets"].push(params);
            }
        })

    } else {
        console.log(`文件路径: ${rootPath}未找到!`);
    }
}

这样子大家就可以获得大家所须要的连接点树了.

获得新的标准图集位置信息

大家对文件夹名称的实际操作早已进行, 此刻大家就必须思索.

怎样把这种零散的图片打包到一张图片上.

散图有两个信息内容, 一个width和一个height, 实际上也是一个矩形框.

大家目前时需做的是把这种不一样总面积的矩形框放进一个具备较大宽度的大矩形框中.


断开照片, 从矩形框置放下手

二维矩形框装车优化算法有许多, 我这里采用一种非常简单的.

最先获得一个具备较大宽度的矩形框小盒子.

大家先放进一个矩形框A, 这样子, 剩下地区就会有二块: 矩形框A的右侧矩形框A的下面.

3.png

随后大家再次放进矩形框B, 可以先右再下, 随后根据矩形框B又有二块空缺室内空间.

4.png

依次类推, 大家就可以将适合的矩形框所有放进.

举个事例

把左侧的装散矩形框放进右侧的矩形中, 可以获得:

5.png

可以见到, 大家节约了好多室内空间, 矩形框排序紧密.

假如用编码完成, 是如何的呢?

/** 
 * 明确高宽 w h
 * 空缺地区先放一个, 剩余的找寻右侧和下面
 * 是不是有达到右侧的, 有则 放进 无则 再次解析xml
 * 是不是有达到下面的, 有则 放进 无则 再次解析xml
 */
const Packer = function (w, h) {
    this.root = { x: 0, y: 0, width: w, height: h };
    // /** 配对任何的格子 */
    Packer.prototype.fit = function (blocks) {

        let node;
        for (let i = 0; i < blocks.length; i  ) {
            let block = blocks[i];
            node = this.findNode(this.root, block.width, block.height);
            if (node) {
                let fit = this.findEmptyNode(node, block.width, block.height);
                block.x = fit.x;
                block.y = fit.y;
                block.fit = fit;
            }
        }

    }

    /** 寻找可以放进的连接点 */
    Packer.prototype.findNode = function (node, w, h) {
        if (node.used) {
            return this.findNode(node.rightArea, w, h) || this.findNode(node.downArea, w, h);
        } else if (node.width >= w && node.height >= h) {
            return node;
        } else {
            return null;
        }
    }

    /** 寻找位置 */
    Packer.prototype.findEmptyNode = function (node, w, h) {
        //早已应用过的 删掉 
        node.used = true;
        //右侧室内空间
        node.rightArea = {
            x: node.x   w,
            y: node.y,
            width: node.width - w,
            height: h
        };

        //下边位置
        node.downArea = {
            x: node.x,
            y: node.y   h,
            width: node.width,
            height: node.height - h
        }
        return node;
    }
}

应用递归, 编码量非常少, 可是功能齐全.

可是有一个问题, 假如超过定长定宽, 或是一个矩形框装不完, 大家的计算方法是不容易放进到大矩形框中的.

这样子就有点儿不符合大家的标准图集装包构思了.

因此大家还必须将这一优化算法改善一下;

添加2个自变量, 一个纪录应用的总的地区, 一个纪录未被装进的矩形框.

//纪录应用的总的地区
this.usedArea = { width: 0, height: 0 };
//纪录未被装进的矩形框
this.levelBlocks = [];

详尽编码可以查询源代码中的packing.

自然, 这儿仅仅非常简单的一种二维装车优化算法

也有一种加强版的装车优化算法, 我放到源代码里了, 这儿也就不赘述了, 基本原理基本一致

如今, 大家早已可以将矩形框适合的装车了, 那怎么用去解决成标准图集呢?

界定一个dealImgsPacking方式, 再次去解决大家的连接点树.

这儿使用了咱们的配备项maxCount, 便是为了更好地一张标准图集装不完, 多搞出多张标准图集的功效.

随后大家装包出去的标准图集取名应用文件夹名称 当今是第多张的方式.

`${obj['name']   (count ? "-"   count : '')}`

具体做法如下所示:

MySpritePackTool.prototype.dealImgsPacking = function (obj) {
    let count = 0;
    if (obj.hasOwnProperty("assets")) {
        let newBlocks = obj["assets"];
        obj["assets"] = [];

        while (newBlocks.length > 0 && count < this.options.maxCount) {
            let packer1 = new Packer(this.options.maxSize.width, this.options.maxSize.height);
            packer1.fit(newBlocks);

            let sheets1 = {
                maxArea: packer1.usedArea,
                atlas: newBlocks,
                fileName: `${obj['name']   (count ? "-"   count : '')}`
            };
            newBlocks = packer1.levelBlocks;
            obj["assets"].push(sheets1);
            count  ;
        }
    }
    for (let item in obj) {
        if (obj[item].hasOwnProperty("assets")) {
            this.dealImgsPacking(obj[item]);
        }
    }
}

根据这些方式大家进行了以前的连接点树;

将以前连接点树中的assest变成了一个二维数组, 每一个二维数组原素意味着一张标准图集信息内容.

构造如下所示:

  assets: [
    { 
        maxArea: { width: 180,height: 340 }, 
        atlas: [
            {
                id: 'assets/index/img-3.png',
                width: 190,
                height: 187,
                x: 0,
                y: 0
            }
        ], 
        fileName: 'assets' },
        ...
  ]

我们可以清楚的获得, 装包以后的标准图集, 较大宽高是maxArea, 每份图高宽位置信息是atlas,及其标准图集名字fileName.

下面, 便是最后一步了, 制作新的图片, 并导出图片文件.

留意
我们在应用装包优化算法的情况下, 可以先开展一下根据图片尺寸的排列
那样至今装包出去的图聚会留白艺术更小

标准图集装包并导出

这儿标准图集的制作和导出均是利用了node-images的API;

解析xml以前获得的连接点树, 最先制作一张maxArea尺寸的空缺图象.

images(item["maxArea"].width, item["maxArea"].height)

随后解析xml一张标准图集所须要的图片, 将每一张图片制作到空缺图象上.

//制作空缺图象
let newSprites = images(item["maxArea"].width, item["maxArea"].height);
//制作标准图集
imgObj.forEach(it => {
    newSprites.draw(images(it["id"]), it["x"], it["y"]);
});

随后制作完一张标准图集导出一张.

newSprites.save(`${this.options.outPutPath}/${item['fileName']}.png`);

最终对连接点树递归函数, 制作出全部的标准图集.

实际编码如下所示:

MySpritePackTool.prototype.drawImages = function (obj) {
    let count = 0;
    if (obj.hasOwnProperty("assets")) {
        //装包出一个或好几个标准图集
        let imgsInfo = obj["assets"];
        imgsInfo.forEach(item => {
            if (item.hasOwnProperty("atlas")) {
                let imgObj = item["atlas"];
                // console.log("8888",imgObj)
                //制作一张透明图像
                let newSprites = images(item["maxArea"].width, item["maxArea"].height);
                imgObj.forEach(it => {
                    newSprites.draw(images(it["id"]), it["x"], it["y"]);
                });

                newSprites.save(`${this.options.outPutPath}/${item['fileName']}.png`);
                count  ;
            }
        })
    }

    for (let item in obj) {
        if (obj[item].hasOwnProperty("assets")) {
            this.drawImages(obj[item]);
        }
    }

}

这样子, 大家就大获全胜了,

运作测试一下, 可以获得如下所示的标准图集:

6.png

7.png

实际效果还不错.

怎么使用

组装

npm i sprites-pack-tool

应用

const MySpritePackTool = require("sprites-pack-tool");
const path = require("path");
/** 装包较多递归频次 */
const MAX_COUNT = 2;
//必须生成的标准图集的途径
const assetsPath = path.resolve(._dirname, "./assets");

/** 标准图集封装工具配备*/
const mySpritePackTool = new MySpritePackTool({
    //一个文件夹图片太多或是太长 递归较大频次
    maxCount: MAX_COUNT,
    //必须装包标准图集的文件路径
    assetsPath: assetsPath,
    //导出文件路径
    outPutPath: path.resolve(._dirname, "./res"),
    //一张标准图集装包最大size
    maxSize: { width: 2048,height: 2048}
});
/** 标准图集装包 */
mySpritePackTool.Pack2Sprite();

未来展望

自然, 这一专用工具仅仅第一版, 后面还会继续再次提升并提升新的作用.

  • 优化算法可以再次提升, 如今留白艺术也挺多.

  • 文件夹名称实际操作,可以提升. 例如载入照片可以每一个文件夹名称下一张标准图集.

  • 提升大量配备项, 例如打开图片大小压缩

  • 提升json文档

  • ...

我大概看过下, 销售市场上面有几种标准图集封装工具, 要不根据texturePacker, 要不根据imagemagick;

应用这俩运用对外开放的API也是可以装包标准图集的, 实际效果质量很有可能更强.

可是你还是得附加组装一个运用.

一样的, 你还可以应用webpack的一些loader或是plugins. 目地全是装包标准图集.

文中详细介绍的专用工具较为轻巧, 可是可堪一用, 与此同时拆箱就可以.

后文

有一阵子沒有发表文章了, 这一礼拜天不经意想写一个那样的专用工具, 就付诸行动了, 結果还不错.

假如你也有更快的方法, 可以留有你的评价, 感激不尽~.

热烈欢迎大伙儿拍砖纠正, 小编功底尚浅, 若有不妥请斧正.

源代码

你能在github查询:https://github.com/xdq1553/MySpritesPackTool

你能应用npm安装:https://www.npmjs.com/package/sprites-pack-tool

参照

node-images:https://github.com/zhangyuanwei/node-images

spritesheet:https://github.com/krzysztof-o/spritesheet.js

文章内容粗浅, 望各位吝惜您的评价和关注点赞~

全文详细地址:https://juejin.cn/post/7035809483666227230

创作者:起小就些熊

大量node有关专业知识,请浏览:nodejs 实例教程!!

以上便是从零陪你应用node开发设计一款标准图集封装工具的详尽具体内容,大量请关心自学java网其他相关文章!

WWW.lllT.neT

声明:有的资源来自网络转载,版权归原作者所有,如有侵犯到您的权益请联系邮箱:our333@126.com我们将配合处理!

原文地址:从零陪你应用node开发设计一款标准图集封装工具发布于2021-12-08 10:18:01