Piskel CLI 完整指南:用 piskel-cli 把 .piskel 文件批量导出为 PNG 精灵图与 data-uri
前端图像处理【免费下载链接】piskelA simple web-based tool for Spriting and Pixel art.项目地址https://gitcode.com/gh_mirrors/pi/piskel点击查看免费下载Piskel 不仅是一款浏览器端的像素画/精灵动画编辑器其仓库内还内置了一个名为piskel-cli的命令行工具能够以无界面headless方式复用 Web 应用的完整导出逻辑。读完本文你将掌握piskel-cli的全部命令行参数--scale、--scaledWidth、--scaledHeight、--rows、--columns、--frame、--dataUri、--crop、--dest等的实际行为以及它“驱动 PhantomJS 加载 Piskel 应用 JS 包再调用内部导出控制器”的底层工作原理从而在脚本化工作流中稳定地完成精灵图sprite sheet导出。一、Piskel CLI 是什么piskel-cli是 Piskel 仓库对像素编辑应用的一次“命令行封装”它把 cli/README.md 中声明的核心能力概括为一句话——Wraps the Piskel pixel editing application to enable similar export options via the command line即让命令行获得与网页版设置面板中相近的导出选项。在 package.json 中可以看到它作为 npm bin 入口注册bin: { piskel-root: ./misc/scripts/piskel-root, piskel-cli: ./cli/index.js }也就是说安装 Piskel 包后piskel-cli会作为全局命令可用。仓库另外还提供了一个辅助命令piskel-root其实现非常简单见 misc/scripts/piskel-root// Writes the absolute path to the release build root to stdout var path require(path); process.stdout.write(path.resolve(__dirname, ../../dest/prod) \n);它只负责把生产构建输出目录dest/prod的绝对路径写到标准输出方便其他工具定位构建产物。而真正干活的 CLI 代码全部集中在cli/目录下的三个文件文件角色cli/index.jsNode 侧入口解析命令行参数、校验输入、查找应用 JS 包、启动 PhantomJS 子进程cli/piskel-export.jsPhantomJS 脚本创建空白页面、注入 Piskel 应用 JS、触发页面内导出逻辑cli/export-png.js页面内执行体调用 Piskel 内部控制器完成裁剪/缩放/渲染并回传画布尺寸二、安装与环境准备2.1 两种安装方式cli/README.md 给出两种安装方式方式一直接从上游 tarball 全局安装npm install -g https://github.com/piskelapp/piskel/tarball/master方式二克隆仓库后本地安装并npm linkgit clone https://github.com/piskelapp/piskel.git cd piskel npm install npm link第二种方式的好处是可以直接对源码做调试链接后piskel-cli命令会指向本地仓库中的 cli/index.js。2.2 关键前提必须先有生产构建产物这是使用 CLI 最容易被忽视的一点。cli/index.js 在启动子进程前会先在构建产物目录中寻找应用 JS 包// Get path to Piskels app js bundle let piskelAppJsDir path.resolve(__dirname /../dest/prod/js/); let minJsFiles fs.readdirSync(piskelAppJsDir).filter(filename filename.indexOf(min) -1); let piskelAppJsFileName minJsFiles[0]; let piskelAppJsPath (piskelAppJsFileName) ? path.join(piskelAppJsDir, piskelAppJsFileName) : ; if (!fs.existsSync(piskelAppJsPath)) { console.error(Piskels application JS file not found in: ${piskelAppJsDir}. Run prod build and try again.); return; }逻辑非常明确在dest/prod/js/目录中查找文件名包含min的 JS 文件如果找不到直接报错并提示Run prod build and try again。因此无论是方式一还是方式二运行前都必须先执行一次生产构建package.json 中的build脚本npm run build:sprites vite build node scripts/partials.js确保dest/prod目录及其中打包后的应用 JS 存在。package.json 中main: ./dest/prod/index.html、files: [dest/prod, ...]也印证了dest/prod是正式发布的构建输出根目录。2.3 运行依赖说明从 cli/index.js 可以看到 CLI 通过require(phantomjs)获取 PhantomJS 可执行文件路径const phantomjs require(phantomjs); const binPath phantomjs.path;而 package.json 的运行时dependencies中只声明了minimist用于参数解析。也就是说phantomjs这个 Node 包需要能在运行环境中被解析到否则入口脚本在require阶段就会失败这是当前仓库实现下的一个实际前提使用时请注意运行环境的依赖完整性。三、完整参数速查表cli/README.md 列出了 9 个示例命令结合 cli/index.js 中minimist的默认值配置与 cli/export-png.js 中的参数消费逻辑完整参数如下表参数默认值说明位置参数.piskel 文件路径必填不传或文件不存在时打印Path to a .piskel file is required/No such file: xxx并退出--scale n1整数缩放倍率对应应用内导出缩放zoom--scaledWidth n无按单帧目标宽度反推缩放比例zoom scaledWidth / piskel.getWidth()--scaledHeight n无按单帧目标高度反推缩放比例zoom scaledHeight / piskel.getHeight()优先级低于--scaledWidth--rows n无精灵图行数单行布局常用--rows 1--columns n无精灵图列数单列布局常用--columns 1--frame n无只导出指定帧索引从 0 开始0为第一帧--dataUrifalse额外生成一个包含 PNG>let args minimist(process.argv.slice(2), { default: { crop: false, dataUri: false, debug: false, scale: 1 }, });输出文件的确定逻辑在 cli/index.jsconst dest args.dest || path.basename(src, .piskel);即未传--dest时输出为当前工作目录下与.piskel文件同名的.png例如snow-monster.piskel→snow-monster.png。README 中的全部示例命令以下命令完整继承自 cli/README.md可直接复制使用# 以应用默认设置导出 .piskel 为 png 精灵图 piskel-cli snow-monster.piskel # 导出 5 倍缩放的精灵图 piskel-cli snow-monster.piskel --scale 5 # 按单帧目标宽度缩放 piskel-cli snow-monster.piskel --scaledWidth 435 # 按单帧目标高度缩放 piskel-cli snow-monster.piskel --scaledHeight 435 # 导出为单列精灵图 piskel-cli snow-monster.piskel --columns 1 # 导出为单行精灵图 piskel-cli snow-monster.piskel --rows 1 # 只导出某一帧0 表示第一帧 piskel-cli snow-monster.piskel --frame 3 # 额外导出一个包含>const options { dest: dest, zoom: args.scale, crop: !!args.crop, rows: args.rows, columns: args.columns, frame: args.frame, dataUri: !!args.dataUri, debug: args.debug, piskelAppJsPath: piskelAppJsPath, scaledWidth: args.scaledWidth, scaledHeight: args.scaledHeight }; const childArgs [ path.join(__dirname, piskel-export.js), piskelFile, JSON.stringify(options) ];注意.piskel文件内容JSON 字符串与optionsJSON 字符串都是作为命令行参数传给子脚本的。另外当--debug开启时会在子进程参数前插入远程调试开关cli/index.jsif (args.debug) { childArgs.unshift( --remote-debugger-port9035, --remote-debugger-autorunyes ); }这为排查 PhantomJS 页面内逻辑提供了入口——该参数未出现在 cli/README.md 中但源码支持。4.2 PhantomJS 脚本cli/piskel-export.js注入应用并反序列化cli/piskel-export.js 运行在 PhantomJS 环境内// Create page w/ canvas const page require(webpage).create(); page.content htmlbody/body/html; // Inject Piskel JS page.injectJs(options.piskelAppJsPath); // Run page logic page.evaluate(function (piskelFile, options, onPageEvaluate) { document.body.style.margin 0; // Deserialize piskel file and run exporters page evaluate task pskl.utils.serialization.Deserializer.deserialize(piskelFile, function (piskel) { onPageEvaluate(window, options, piskel); }); }, piskelFile, options, exporter.onPageEvaluate);要点通过page.injectJs把整个 Piskel 应用 JS 包注入空白页面页面中因此存在全局命名空间pskl包含utils.serialization、controller.piskel、tools.transform等文件内容交由应用自带的反序列化器pskl.utils.serialization.Deserializer.deserialize还原为piskel模型对象导出完成后页面通过callPhantom回传数据父函数page.onCallback中调用exporter.onPageExit写文件然后phantom.exit(0)退出。4.3 页面内执行体cli/export-png.js复用应用控制器cli/export-png.js 的onPageEvaluate是全部导出参数的真正消费方// Setup piskelController var piskelController new pskl.controller.piskel.PiskelController(piskel); pskl.app.piskelController piskelController; piskelController.init();它直接实例化了与 Web 版相同的应用主控制器pskl.controller.piskel.PiskelController并挂到pskl.app全局上这是多个内部工具类读取应用状态的约定入口。后续所有行为都建立在这一次“无 DOM 化”的初始化之上。裁剪--crop// Apply crop if enabled if (options.crop) { // Mock selection manager to avoid errors during crop pskl.app.selectionManager {}; // Setup crop tool var crop new pskl.tools.transform.Crop(); // Perform crop crop.applyTransformation(); // Get cropped piskel piskel piskelController.getPiskel(); }这里通过把pskl.app.selectionManagermock 成空对象使 Crop 工具 走“无选区”分支——用TransformUtils.getBoundaries(frames)计算所有帧、所有图层内容的外接矩形并整体裁剪而不是按用户选区裁剪。结合 Crop.js 的applyTool_可以看到它先用moveFramePixels平移各帧像素再用ResizeUtils.resizePiskelorigin: TOP-LEFT重设画布尺寸最后setPiskel替换当前项目。因此--crop的语义是“裁掉四周空白保留实际绘制内容”且作用于全部帧与图层。缩放--scale / --scaledWidth / --scaledHeight// Mock exportController to provide zoom value based on cli args var exportController { getExportZoom: function () { var zoom options.zoom; if (options.scaledWidth) { zoom options.scaledWidth / piskel.getWidth(); } else if (options.scaledHeight) { zoom options.scaledHeight / piskel.getHeight(); } return zoom; } };这是对 Web 版 ExportController 接口getExportZoom()的精确复刻与替换——Web 版中该方法返回“导出面板宽度输入值 / 画布宽度”CLI 则用命令行参数计算。优先级从高到低为--scaledWidthzoom scaledWidth / 画布宽非整数缩放按比例精确命中目标宽度--scaledHeightzoom scaledHeight / 画布高--scale直接使用整数倍率默认 1与 Web 版UserSettings.EXPORT_SCALE的默认值一致见 UserSettings.js。缩放本身由 ImageResizer.resize 完成并且显式传入smoothingEnabled falseif (zoom ! 1) { // Scale rendered frame canvas pskl.utils.ImageResizer.resize(canvas, canvas.width * zoom, canvas.height * zoom, false); }关闭图像平滑意味着浏览器画布会走最近邻插值放大后仍是锐利的像素块这正是像素画放大的期望效果也解释了为什么--scaledWidth 435这类非整数目标值不会把精灵图“抹糊”。行列布局--rows / --columns// Mock getColumns and getRows to use values from cli arguments pngExportController.getColumns_ function () { if (options.columns) return options.columns; if (options.rows) { return Math.ceil(piskelController.getFrameCount() / pngExportController.getRows_()); } else { return pngExportController.getBestFit_(); } }; pngExportController.getRows_ function () { if (options.columns !options.rows) { return Math.ceil(piskelController.getFrameCount() / pngExportController.getColumns_()); } return options.rows; };这段代码直接覆盖了 PngExportController 中原本读取 DOM 输入框的getColumns_/getRows_两个私有方法把布局策略切换为命令行驱动。其决策顺序是传了--columns列数取指定值行数取ceil(帧数 / 列数)--columns 1即整张图一列只传了--rows行数取指定值列数取ceil(帧数 / 行数)--rows 1即整张图一行都不传回退到应用默认的getBestFit_()。回退的“最佳适配”算法来自 PngExportController.getBestFit_var ratio this.piskelController.getWidth() / this.piskelController.getHeight(); var frameCount this.piskelController.getFrameCount(); var bestFit Math.round(Math.sqrt(frameCount / ratio)); return pskl.utils.Math.minmax(bestFit, 1, frameCount);即以sqrt(帧数 / 宽高比)取整作为列数并约束在[1, 帧数]区间内让精灵图整体尽量接近正方形——这就是piskel-cli snow-monster.piskel不带行列参数时“app defaults”的含义。单帧导出--frame与精灵图渲染if (options.frame -1) { // Render a single frame canvas piskelController.renderFrameAt(options.frame, true); ... } else { // Render the sprite sheet canvas pngExportController.createPngSpritesheet_(); }单帧分支--frame 3时调用renderFrameAt(3, true)。该方法定义于 PiskelController内部委托 LayerUtils.flattenFrameAt 把该帧的所有可见图层合成为一张 canvas随后若zoom ! 1再按前述方式缩放。注意帧索引从 0 开始README 原话0 is first frame。精灵图分支createPngSpritesheet_()PngExportController内部用 PiskelRenderer 逐帧渲染并按columns平铺——renderAsCanvas中每帧的落点为posX (i % columns) * 宽、posY floor(i / columns) * 高即从左到右、从上到下依次排布全部帧都绘制在一张大画布上最后整体缩放。4.4 文件落盘onPageExit渲染完成的 canvas 被挂到页面body上后导出逻辑通过callPhantom把画布宽高传回 PhantomJS 层由 cli/export-png.js 的onPageExit完成落盘function onPageExit(page, options, data) { // Set clip for output image if (data.width data.height) { page.clipRect { top: 0, left: 0, width: data.width, height: data.height }; } console.log(\n Generated file(s):); const dest options.dest.replace(.png, ) .png; // Render page to the output image page.render(dest); console.log( dest); if (options.dataUri) { const dataUriPath options.dest .datauri; const dataUri data:image/png;base64, page.renderBase64(PNG); // Write>赞分享前端图像处理【免费下载链接】piskelA simple web-based tool for Spriting and Pixel art.项目地址https://gitcode.com/gh_mirrors/pi/piskel点击查看免费下载相关推荐Piskel 发布实践从 RELEASE.md 解析 piskel / piskel-website 双仓库发布流水线Piskel 发布实践从 RELEASE.md 解析 piskel / piskel website 双仓库发布流水线 Piskel https://link前端图像处理推荐项目Piskel推荐项目Piskel Piskel 是一个在线像素艺术编辑器专为创建像素完美的图像而设计。无论你是游戏开发者、像素艺术家还是只是喜欢复古风格的图像都可以使前端图像处理Piskel用户行为分析Google Analytics事件跟踪实现Piskel用户行为分析Google Analytics事件跟踪实现 项目概述 Piskel是一款基于Web的像素艺术创作工具通过直观的界面和丰富的绘图功能前端图像处理上一篇使用 Rube MCP 自动化 Gladia 任务awesome-codex-skills 中 gladia-automation 技能实战指南下一篇gpui-kit Popup 完全指南触发器测量、锚点定位与延迟渲染的浮动层宿主创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

AI漫剧跨集角色一致性方案:基于向量数据库的特征管理与检索实践

AI漫剧跨集角色一致性方案:基于向量数据库的特征管理与检索实践

制作 AI 漫剧推文短视频时,单集内角色一致可以通过 LoRA 和提示词锁定解决。但当系列扩展到 10 集以上,跨集角色漂移会成为新问题。本文讨论用向量数据库管理角色特征,实现跨集一致性校验与检索。若不想自建这套系统,也可参考知漫…

2026/10/14 3:09:32 阅读更多 →
网络通信分层模型与DoS防御实战解析

网络通信分层模型与DoS防御实战解析

1. 网络通信基础与分层模型解析网络通信模型是理解现代互联网运作机制的基石。就像建造一栋大楼需要从地基到屋顶分层施工一样,网络通信也需要分层处理不同层级的任务。最经典的OSI七层模型和实际广泛应用的TCP/IP四层模型,构成了我们日常上网、传输文件…

2026/10/14 3:09:32 阅读更多 →
MySQL常见函数详解:从字符串到日期与聚合的实战指南

MySQL常见函数详解:从字符串到日期与聚合的实战指南

MySQL中的常见函数,是每个写SQL的人绕不开的基本功。我做数据库开发这些年,发现一个规律:那些看起来很复杂的数据处理任务,底层往往就是几个常见函数在组合发力。字符串拼接截取、日期格式化与计算、数值精度控制、分组后聚合汇总…

2026/10/14 3:09:32 阅读更多 →

最新新闻

思科设备本地管理三通道:CONSOLE、VTY与WEB深度解析

思科设备本地管理三通道:CONSOLE、VTY与WEB深度解析

1. 为什么“本地管理”不是可选项,而是网络设备运维的第一道生死线在某高校实验室部署一批新采购的思科交换机时,我遇到过一个典型场景:所有设备已上架通电,物理链路也完成了双绞线直连,但整栋楼的终端突然全部失联。排…

2026/10/14 3:46:39 阅读更多 →
Windows系统应用集体失效?UWP重注册与系统修复全攻略

Windows系统应用集体失效?UWP重注册与系统修复全攻略

这次要排查的问题非常典型:Windows 系统自带的照片、计算器、微软商店、视频播放器全都打不开,任务栏图标下方出现一条横线,点击后没有任何反应。这不是某一个应用坏了,而是系统级问题——大概率是 UWP 应用的注册信息、应用商店组…

2026/10/14 3:46:39 阅读更多 →
AI加持的工业三维模型网页端展示方案与实战解析

AI加持的工业三维模型网页端展示方案与实战解析

从接手一个工业设备的三维展示需求开始,聊起为什么我没给客户推荐再装一套CAD,而是All in了网页端方案,以及AI在这个过程中扮演的角色。这个项目做下来,从最初的模型轻量化到最终的浏览器实时交互,踩了不少坑&#xff…

2026/10/14 3:46:39 阅读更多 →
Ubuntu下Python3 MQTT订阅端性能测试:Mosquitto吞吐与延迟实战

Ubuntu下Python3 MQTT订阅端性能测试:Mosquitto吞吐与延迟实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 3:46:39 阅读更多 →
2027产品运营秋招:数学与应用数学专业零经验,如何用项目证明业务能力?

2027产品运营秋招:数学与应用数学专业零经验,如何用项目证明业务能力?

一、零经验可以投产品运营,但要边准备边投递数学与应用数学专业可以把产品运营作为秋招方向,不必因为没有经验就先转去做数据分析师。数学训练能够帮助你理解指标、拆解问题,但企业还需要看到你理解用户、推动活动、协调执行的能力。数据分析…

2026/10/14 3:46:39 阅读更多 →
sqli-labs靶场实战指南:从部署到SQL注入自动化盲注脚本

sqli-labs靶场实战指南:从部署到SQL注入自动化盲注脚本

简介:sqli-labs 是一款经典的开源 SQL 注入练习靶场,内置从基础到进阶的十余种注入场景,涵盖联合查询、报错注入、布尔盲注、时间盲注、堆叠注入等常见类型,适合网络安全从业者、渗透测试工程师及信息安全专业学生用于系统学习 We…

2026/10/14 3:45:39 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →