UNPKG

spritesheet-creator

Version:
729 lines (631 loc) 23.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _jimp = _interopRequireDefault(require("jimp")); var _globPromise = _interopRequireDefault(require("glob-promise")); var _lodash = _interopRequireDefault(require("lodash")); var _path = _interopRequireDefault(require("path")); var _packer = _interopRequireDefault(require("packer")); var _sorter = _interopRequireDefault(require("sorter")); var _smart_crop = _interopRequireDefault(require("smart_crop")); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var DefaultOptions = { trim: true, padding: 1, divisibleByTwo: true, square: false, sortMethod: 'width', packAlgorithm: 'growing-binpacking', powerOfTwo: true }; var SpritesheetGenerator = /*#__PURE__*/ function () { function SpritesheetGenerator(_ref) { var log = _ref.log, exportFormat = _ref.exportFormat, outputTexturePath = _ref.outputTexturePath, outputDataPath = _ref.outputDataPath, options = _ref.options; (0, _classCallCheck2["default"])(this, SpritesheetGenerator); this.log = log; this.exportFormat = exportFormat; this.outputTexturePath = outputTexturePath; this.outputDataPath = outputDataPath; this.options = options || {}; for (var key in DefaultOptions) { if (this.options[key] === undefined) { this.options[key] = DefaultOptions[key]; } } this.log.info(this.options); } (0, _createClass2["default"])(SpritesheetGenerator, [{ key: "generateFurther", value: function generateFurther() { var _this = this; return _regenerator["default"].async(function generateFurther$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: this.printStats(); if (this.options.trim) { this.trimImages(); this.printStats(); } this.pad(); this.pack(); this.determineCanvasSize(); this.calcRealPositions(); _context.next = 8; return _regenerator["default"].awrap(Promise.all([this.generateTexture().then(function () { return _this.saveTexture(); }), this.generateTextureData()])); case 8: return _context.abrupt("return", this.files); case 9: case "end": return _context.stop(); } } }, null, this); } }, { key: "generateFromMemory", value: function generateFromMemory(files) { var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file; return _regenerator["default"].async(function generateFromMemory$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: this.files = files; _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; _context2.prev = 4; _iterator = this.files[Symbol.iterator](); case 6: if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { _context2.next = 20; break; } file = _step.value; if (file.image) { _context2.next = 10; break; } throw new Error("file is missing image"); case 10: _context2.next = 12; return _regenerator["default"].awrap(_jimp["default"].create({ data: file.image.bitmap.data, width: file.image.bitmap.width, height: file.image.bitmap.height })); case 12: file.image = _context2.sent; file.padding = { left: 0, right: 0, up: 0, down: 0 }; file.margin = { left: 0, right: 0, up: 0, down: 0 }; file.padded = { x: 0, y: 0, width: 0, height: 0, area: 0 }; file.real = { x: 0, y: 0, width: 0, height: 0, area: 0 }; case 17: _iteratorNormalCompletion = true; _context2.next = 6; break; case 20: _context2.next = 26; break; case 22: _context2.prev = 22; _context2.t0 = _context2["catch"](4); _didIteratorError = true; _iteratorError = _context2.t0; case 26: _context2.prev = 26; _context2.prev = 27; if (!_iteratorNormalCompletion && _iterator["return"] != null) { _iterator["return"](); } case 29: _context2.prev = 29; if (!_didIteratorError) { _context2.next = 32; break; } throw _iteratorError; case 32: return _context2.finish(29); case 33: return _context2.finish(26); case 34: return _context2.abrupt("return", this.generateFurther()); case 35: case "end": return _context2.stop(); } } }, null, this, [[4, 22, 26, 34], [27,, 29, 33]]); } }, { key: "generateFromFiles", value: function generateFromFiles(inputPatterns) { return _regenerator["default"].async(function generateFromFiles$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: _context3.next = 2; return _regenerator["default"].awrap(this.getFileList(inputPatterns)); case 2: if (!(this.files.length === 0)) { _context3.next = 5; break; } this.log.warn('no files were found, finishing'); return _context3.abrupt("return", []); case 5: _context3.next = 7; return _regenerator["default"].awrap(this.readImages()); case 7: return _context3.abrupt("return", this.generateFurther()); case 8: case "end": return _context3.stop(); } } }, null, this); } }, { key: "formatPercentChange", value: function formatPercentChange(oldValue, newValue) { var percentChange = newValue / oldValue * 100 - 100; return "".concat(percentChange > 0 ? '+' : '').concat(percentChange.toFixed(2), "%"); } }, { key: "printStats", value: function printStats() { var stats = { totalBytes: 0, totalPixels: 0 }; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = this.files[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var file = _step2.value; var image = file.image; if (!image) continue; stats.totalBytes += image.bitmap.data.length; stats.totalPixels += image.bitmap.width * image.bitmap.height; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { _iterator2["return"](); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } var btChangeString = ''; var pxChangeString = ''; if (this.stats) { btChangeString = " (".concat(this.formatPercentChange(this.stats.totalBytes, stats.totalBytes), ")"); pxChangeString = " (".concat(this.formatPercentChange(this.stats.totalPixels, stats.totalPixels), ")"); } this.log.info("".concat(stats.totalBytes, " total bytes").concat(btChangeString)); this.log.info("".concat(stats.totalPixels, " total pixels").concat(pxChangeString)); this.stats = stats; } }, { key: "saveTexture", value: function saveTexture() { return _regenerator["default"].async(function saveTexture$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: if (this.outputTexturePath) { _context4.next = 3; break; } this.log.info("skipping texture save"); return _context4.abrupt("return"); case 3: this.log.info("saving texture to ".concat(this.outputTexturePath)); _context4.next = 6; return _regenerator["default"].awrap(this.texture.write(this.outputTexturePath)); case 6: this.log.info("done saving texture"); case 7: case "end": return _context4.stop(); } } }, null, this); } }, { key: "getFileList", value: function getFileList(inputPatterns) { return _regenerator["default"].async(function getFileList$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: this.log.info("getting file list from ".concat(inputPatterns.join(','))); _context5.t0 = _lodash["default"]; _context5.next = 4; return _regenerator["default"].awrap(Promise.all(inputPatterns.map(function (pattern) { return (0, _globPromise["default"])(pattern).then(function (files) { return files.map(function (name) { return { pattern: pattern, name: name, padding: { left: 0, right: 0, up: 0, down: 0 }, margin: { left: 0, right: 0, up: 0, down: 0 }, padded: { x: 0, y: 0, width: 0, height: 0, area: 0 }, real: { x: 0, y: 0, width: 0, height: 0, area: 0 } }; }); }); }))); case 4: _context5.t1 = _context5.sent; this.files = _context5.t0.flatten.call(_context5.t0, _context5.t1); this.log.info("got ".concat(this.files.length, " files")); case 7: case "end": return _context5.stop(); } } }, null, this); } }, { key: "readImages", value: function readImages() { return _regenerator["default"].async(function readImages$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: this.log.info("reading files into memory"); _context6.next = 3; return _regenerator["default"].awrap(Promise.all(this.files.map(function (file) { return _jimp["default"].read(file.name).then(function (image) { file.image = image; file.real = { width: image.bitmap.width, height: image.bitmap.height, x: 0, y: 0, area: image.bitmap.width * image.bitmap.height }; })["catch"](function (err) { throw new Error("couldn't read ".concat(file.name, ": ").concat(err)); }); }))); case 3: case "end": return _context6.stop(); } } }, null, this); } }, { key: "trimImages", value: function trimImages() { this.log.info("trimming images"); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = this.files[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var file = _step3.value; var image = file.image; if (!image) continue; var _smartCrop = (0, _smart_crop["default"])({ image: image }), margin = _smartCrop.cropped; file.real.width = image.bitmap.width; file.real.height = image.bitmap.height; file.real.area = file.real.width * file.real.height; file.margin = margin; } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) { _iterator3["return"](); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } }, { key: "pad", value: function pad() { this.log.info("padding files"); var padding = this.options.padding ? this.options.padding : 0; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = this.files[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var file = _step4.value; var image = file.image; if (!image) continue; file.padding = { up: padding, right: padding, down: padding, left: padding }; file.padded.width = file.real.width + padding * 2; file.padded.height = file.real.height + padding * 2; if (this.options.divisibleByTwo) { if (file.padded.width & 1) { file.padded.width += 1; file.padding.left++; } if (file.padded.height & 1) { file.padded.height += 1; file.padding.up++; } } file.padded.area = file.padded.width * file.padded.height; } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) { _iterator4["return"](); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } } }, { key: "roundToPowerOfTwo", value: function roundToPowerOfTwo(value) { var powers = 2; while (value > powers) { powers *= 2; } return powers; } }, { key: "pack", value: function pack() { var sortMethod = this.options.sortMethod; if (!sortMethod) { throw new Error("sorting algorithm not found"); } this.log.info("sorting files using '".concat(sortMethod, "' method")); (0, _sorter["default"])(sortMethod, this.files); var algorithm = this.options.packAlgorithm; if (!algorithm) { throw new Error("packing algorithm not found"); } this.log.info("packing using '".concat(algorithm, "' algorithm")); (0, _packer["default"])({ algorithm: algorithm, files: this.files, options: this.options }); } }, { key: "calcRealPositions", value: function calcRealPositions() { var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = this.files[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var file = _step5.value; file.real.x = file.padded.x + file.padding.left; file.real.y = file.padded.y + file.padding.up; } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) { _iterator5["return"](); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } } }, { key: "determineCanvasSize", value: function determineCanvasSize() { this.log.info("detemining minimum canvas size"); var _this$options = this.options, width = _this$options.width, height = _this$options.height; if (!width || !height) { throw new Error("couldn't detemine the minimum canvas size"); } this.log.info("minimum canvas size required: ".concat(width, "x").concat(height)); if (this.options.square) { width = height = Math.max(width, height); this.log.info("square texture required: ".concat(width, "x").concat(height)); } if (this.options.powerOfTwo) { width = this.roundToPowerOfTwo(width); height = this.roundToPowerOfTwo(height); this.log.info("power of two required: ".concat(width, "x").concat(height)); } if (this.options.maxTextureSize) { if (width > this.options.maxTextureSize || height > this.options.maxTextureSize) { throw new Error("texture size too large (> ".concat(this.options.maxTextureSize, ")")); } } this.log.info("determined final texture size: ".concat(width, "x").concat(height)); this.options = _objectSpread({}, this.options, { width: width, height: height }); } }, { key: "generateTexture", value: function generateTexture() { var _iteratorNormalCompletion6, _didIteratorError6, _iteratorError6, _iterator6, _step6, file; return _regenerator["default"].async(function generateTexture$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: this.log.info("generating texture"); _context7.next = 3; return _regenerator["default"].awrap(_jimp["default"].create(this.options.width, this.options.height)); case 3: this.texture = _context7.sent; _iteratorNormalCompletion6 = true; _didIteratorError6 = false; _iteratorError6 = undefined; _context7.prev = 7; for (_iterator6 = this.files[Symbol.iterator](); !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { file = _step6.value; this.texture.composite(file.image, file.real.x, file.real.y); } _context7.next = 15; break; case 11: _context7.prev = 11; _context7.t0 = _context7["catch"](7); _didIteratorError6 = true; _iteratorError6 = _context7.t0; case 15: _context7.prev = 15; _context7.prev = 16; if (!_iteratorNormalCompletion6 && _iterator6["return"] != null) { _iterator6["return"](); } case 18: _context7.prev = 18; if (!_didIteratorError6) { _context7.next = 21; break; } throw _iteratorError6; case 21: return _context7.finish(18); case 22: return _context7.finish(15); case 23: this.log.info("generated texture of ".concat(this.texture.bitmap.data.length, " bytes")); case 24: case "end": return _context7.stop(); } } }, null, this, [[7, 11, 15, 23], [16,, 18, 22]]); } }, { key: "generateTextureData", value: function generateTextureData() { var exportPlugin; return _regenerator["default"].async(function generateTextureData$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: this.log.info("save data to '".concat(this.outputDataPath, "' with '").concat(this.exportFormat, "' export format")); this.log.info("loading export plugin"); _context8.prev = 2; // $FlowFixMe exportPlugin = require(_path["default"].join(__dirname, "data_output_plugins/".concat(this.exportFormat, ".js")))["default"]; _context8.next = 9; break; case 6: _context8.prev = 6; _context8.t0 = _context8["catch"](2); throw new Error("unsupport texture export format: ".concat(this.exportFormat)); case 9: _context8.next = 11; return _regenerator["default"].awrap(exportPlugin({ projectRoot: this.options.projectRoot, files: this.files, outputDataPath: this.outputDataPath, outputTexturePath: this.outputTexturePath, log: this.log })); case 11: case "end": return _context8.stop(); } } }, null, this, [[2, 6]]); } }]); return SpritesheetGenerator; }(); exports["default"] = SpritesheetGenerator;