ホームページ > 記事 > ウェブフロントエンド > ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。
この記事では、node を使用してアトラス パッケージ ツールを手書きする方法を説明します。一定の参考価値があります。皆様のお役に立てれば幸いです。
非常に便利なクロスプラットフォーム画像エンコードおよびデコード ライブラリを偶然発見しましたnode-images.
その API をよく読んでください。それを使用して スプライト アトラス を作成するというアイデアが思いつきました。
そこで、このツール sprites-pack-tool
.
# が誕生しました。 ##github で表示できますhttps://github.com/xdq1553/MySpritesPackToolnpm を使用してインストールできますhttps://www .npmjs.com /package/sprites-pack-tool
Sprite Atlas.
たとえば、誰もがよく知っていると思います。 、以下を入力してください。いくつかの写真が 1 つに結合されています。
このアルバムは、紹介されたツールを使用して私がパッケージ化して結合しています。この記事では、合成された画像の品質は依然として非常に高いです。なぜアトラスを使用する必要があるのかWeb 開発私たちはWeb 開発では、ブラウザは画像を表示するために毎回サーバー リソースを要求する必要があります。たとえば、それぞれ 4K の3 リクエスト と には根本的な違いがあります。 1 つのリクエストは 12k ですが、多くの場合、リクエストは 3 * 4k.
ではありません。アトラスを使用すると、リソースの読み込みを最適化し、Web サイトのパフォーマンスを向上させることができます。 .ゲーム開発 ゲーム開発では、アトラスの使用が非常に重要です。一般的なフレーム アニメーションであっても、SVGA などのアニメーション ソリューションであっても、画像ごとにリソースが要求されることはありません。続き 当時、私たちは皆それらをアトラスにパッケージ化しており、アトラス パッケージ化ツールtexturepacker の方がさらに人気がありました。
ピクチャ アルバムの使用方法は次のとおりです。不可欠です。
これを以下で実行してみましょう。アトラス パッケージ化ツールの作成方法を見てみましょう。ツール設計アトラスを開発するにはどのようなスキルが必要ですかパッケージ化ツール スクリプト。node.jsプログラミング能力
#アルバムは、複数の散在する写真をつなぎ合わせて構成されています。
/** 图集打包对象 */ 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;
ファイルをトラバースしてノード ツリーを生成します
入力パラメータは次のとおりです。できる限り少ないので、プログラムがフォルダーを横断する必要があります。
たとえば、次のディレクトリ ツリーがあります:|--assets |--index |--img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。 |--img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。 |--login |--img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。 |--img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。 |--img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。各フォルダーにアトラスをパッケージ化する必要があります。
思考: どのようなデータ構造が必要か?
まずは js が便利 分析のためにオブジェクトを決めます 各層画像情報コンテナassets;
含まれる画像識別子keys
;フォルダー名が必要です。アルバムは後で
name
次に、フォルダーの各層の前に同じオブジェクトを配置します。
構造は次のとおりです:
{ assets: [ { id: 'assets/img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。', width: 190, height: 187 }, ... ], name: 'assets', keys: 'img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。,img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。,', index: { assets: [ { id: 'assets/index/img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。', width: 190, height: 187 }, ... ], name: 'index', keys: 'img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。,img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。,' }, login: { assets: [ { id: 'assets/login/img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。', width: 190, height: 187 } ], name: 'index', keys: 'img-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。,' }, }パッケージ化する必要があるすべてのファイルとフォルダーをすでに入手できることを見つけるのは難しくありません。
では、それをプログラムで実装するにはどうすればよいでしょうか?
主にnodejsの
fsモジュールを使用して、再帰的にフォルダを操作し、必要なノードツリーを出力します。書く際には、画像なのか画像なのかを判断する必要があるので注意してください。 Folder.
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}不存在!`); } }この方法で、必要なノード ツリーを取得できます。
新しいアトラスの位置情報を取得します
フォルダーに対する操作は完了しました。考える必要があります。これらの分散した画像を 1 つの画像に詰め込む方法。分散した画像には、高さ#の 2 つの情報があります。 ## は実際には長方形です。
我们现在所要做的就是把这些不同面积的矩形放到一个具有最大长宽的大矩形中.
跳开图片, 从矩形放置入手
二维矩形装箱算法有不少, 我这里选用一种比较简单的.
首先得到一个具有最大长宽的矩形盒子.
我们先放入一个矩形A, 这样子, 剩余区域就有两块: 矩形A的右边和矩形A的下边.
然后我们继续放入矩形B, 可以先右再下, 然后基于矩形B又有两块空白空间.
依次类推, 我们就可以将合适的矩形全部放入.
举个例子
把左边的散装矩形放入右边的矩形框中, 可以得到:
可以看到, 我们节省了很多空间, 矩形排列紧凑.
如果用代码实现, 是怎么样的呢?
/** * 确定宽高 w h * 空白区域先放一个, 剩下的寻找右边和下边 * 是否有满足右边的, 有则 放入 无则 继续遍历 * 是否有满足下边的, 有则 放入 无则 继续遍历 */ 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; } }
使用递归, 代码量很少, 但是功能强大.
但是有一个问题, 如果超出定长定宽, 或者一个矩形装不完, 我们的算法是不会放入到大矩形中的.
这样子就有点不满足我们的图集打包思路了.
所以我们还需要将这个算法改进一下;
加入两个变量, 一个记录使用的总的区域, 一个记录未被装入的矩形.
//记录使用的总的区域 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-ノードを使用してアトラス パッケージング ツールを開発する手順を説明します。', width: 190, height: 187, x: 0, y: 0 } ], fileName: 'assets' }, ... ]
我们可以清晰的得到, 打包之后的图集, 最大宽高是maxArea
, 每张图宽高位置信息是atlas
,以及图集名称fileName
.
接下来, 就是最后一步了, 绘制新的图片, 并输出图片文件.
注意
我们在使用打包算法的时候, 可以先进行一下基于图片大小的排序
这样以来打包出来的图集会留白更小
这里图集的绘制和输出均是使用了node-images
的API;
遍历之前得到的节点树, 首先绘制一张maxArea
大小的空白图像.
images(item["maxArea"].width, item["maxArea"].height)
然后遍历一张图集所需要的图片信息, 将每一张图片绘制到空白图像上.
//绘制空白图像 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]); } } }
这样子, 我们就大功告成了,
运行测试一下, 可以得到如下的图集:
效果还不错.
安装
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-パックツール
参考
node-images:https://github.com/zhangyuanwei/node-images
スプライトシート:https:/ /github.com/krzysztof-o/spritesheet.js
この記事は表面的なものです。コメントやいいねは控えていただければ幸いです~
#元のアドレス: https://juejin.cn/post/7035809483666227230 著者: 子供の頃からのクマノード関連の知識の詳細については、こちらをご覧ください:
nodejs チュートリアル! !
以上がノードを使用してアトラス パッケージング ツールを開発する手順を説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。