この記事では、node を使用してアトラス パッケージ ツールを手書きする方法を説明します。一定の参考価値があります。皆様のお役に立てれば幸いです。
非常に便利なクロスプラットフォーム画像エンコードおよびデコード ライブラリを偶然発見しましたnode-images.
その API をよく読んでください。それを使用して スプライト アトラス を作成するというアイデアが思いつきました。
そこで、このツール sprites-pack-tool
.
# が誕生しました。 ##github で表示できますhttps://github.com/xdq1553/MySpritesPackToolnpm を使用してインストールできますhttps://www .npmjs.com /package/sprites-pack-tool
Sprite Atlas.
たとえば、誰もがよく知っていると思います。 、以下を入力してください。いくつかの写真が 1 つに結合されています。
3 リクエスト と には根本的な違いがあります。 1 つのリクエストは 12k ですが、多くの場合、リクエストは 3 * 4k.
ではありません。アトラスを使用すると、リソースの読み込みを最適化し、Web サイトのパフォーマンスを向上させることができます。 .ゲーム開発 ゲーム開発では、アトラスの使用が非常に重要です。一般的なフレーム アニメーションであっても、SVGA などのアニメーション ソリューションであっても、画像ごとにリソースが要求されることはありません。続き 当時、私たちは皆それらをアトラスにパッケージ化しており、アトラス パッケージ化ツールtexturepacker の方がさらに人気がありました。
ピクチャ アルバムの使用方法は次のとおりです。不可欠です。
これを以下で実行してみましょう。アトラス パッケージ化ツールの作成方法を見てみましょう。ツール設計アトラスを開発するにはどのようなスキルが必要ですかパッケージ化ツール スクリプト。node.jsプログラミング能力
##2 次元長方形ビニング アルゴリズム- ##次に、アトラスをパッケージ化する方法を考えます。
#アルバムは、複数の散在する写真をつなぎ合わせて構成されています。
- ##アトラスのサイズは構成可能である必要があります #各画像がぴったりと収まるようにアトラスのスペースをできるだけ圧縮します。
- #各フォルダーはアトラスにパッケージ化されます。フォルダーが多すぎる場合は考慮する必要があります。 photos
- アトラス ファイルに必要な json を生成し、写真の位置情報を記録する必要がある場合があります
- スクリプトの作成を開始します
- Script IOこれが私の設計方法です。
MySpritePackTool
が必要ですオプション
./** 图集打包对象 */ 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 サイトの他の関連記事を参照してください。

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

この記事では、許可によって保護されたバックエンドとのフロントエンド統合を示し、next.jsを使用して機能的なedtech SaaSアプリケーションを構築します。 FrontEndはユーザーのアクセス許可を取得してUIの可視性を制御し、APIリクエストがロールベースに付着することを保証します

JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。

JavaScriptの最新トレンドには、TypeScriptの台頭、最新のフレームワークとライブラリの人気、WebAssemblyの適用が含まれます。将来の見通しは、より強力なタイプシステム、サーバー側のJavaScriptの開発、人工知能と機械学習の拡大、およびIoTおよびEDGEコンピューティングの可能性をカバーしています。

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境
