diff --git a/package-lock.json b/package-lock.json index 0042d53..bb24a50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "pixaki", - "version": "0.0.10", + "version": "0.0.11", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -73,6 +73,16 @@ "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==", "dev": true }, + "@types/shelljs": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.8.tgz", + "integrity": "sha512-lD3LWdg6j8r0VRBFahJVaxoW0SIcswxKaFUrmKl33RJVeeoNYQAz4uqCJ5Z6v4oIBOsC5GozX+I5SorIKiTcQA==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, "@webassemblyjs/ast": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", diff --git a/package.json b/package.json index 06ed530..d3a93bc 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,19 @@ { "name": "pixaki", - "version": "0.0.10", + "version": "0.0.11", "description": "", "scripts": { "build": "rimraf dist && npx webpack && node chmod && cp src/package.json dist/package.json && cp src/README.md dist/README.md", "link": "cd dist && npm link && cd ..", - "preDeploy": "npm run build && npm run link && npm run test:success", - "test:export:success": "pixaki export testFiles/crate.pixaki", "test:layer:success": "pixaki layer testFiles/crate.pixaki 'Arbitrary Map'", "test:columns:success": "pixaki export testFiles/crate.pixaki --columns=1 && pixaki layer testFiles/crate.pixaki 'Arbitrary Map' --columns=1", "test:outDir:success": "pixaki export 'testFiles/**/*.pixaki' --columns=1 --outDir=OUT_DIR && pixaki layer 'testFiles/**/*.pixaki' 'Arbitrary Map' --columns=1 --outDir=OUT_DIR", "test:success": "npm run test:export:success && npm run test:layer:success && npm run test:columns:success && npm run test:outDir:success", - "test:export:failure": "pixaki export testFiles/crat.pixaki", "test:layer:failure": "pixaki layer testFiles/crate.pixaki 'Nonexistent Layer'", "test:failure": "npm run test:export:failure && npm run test:layer:failure" - }, "main": "src/cli.ts", "author": "", @@ -38,6 +34,7 @@ "@types/glob": "^7.1.3", "@types/imagemagick": "0.0.30", "@types/node": "^14.14.41", + "@types/shelljs": "^0.8.8", "ts-loader": "^9.0.2", "typescript": "^4.2.4", "webpack": "^5.35.0", diff --git a/src/exporter.ts b/src/exporter.ts index 40a7a54..a32045a 100644 --- a/src/exporter.ts +++ b/src/exporter.ts @@ -3,15 +3,18 @@ import { convert } from 'imagemagick'; import { TEMP_FOLDER_NAME } from './constants'; import { temp, DisplayCompleteMessage } from "./helpers"; import { glob } from "glob"; +import { exec } from "shelljs"; export default function (path: string, columns: number, outDir: string) { + // require('events').EventEmitter.defaultMaxListeners = 20; + // process.setMaxListeners(0); + console.log(`\nExporting...`); // TODO: Share duplicate code that exists between this and layer.ts (BaseCommand? GetPixakiFile + BaseArgs?) var fs = require('fs'); var rimraf = require('rimraf'); - var shell = require('shelljs'); var outDir = outDir ? outDir + '/' : ''; var successCount = 0; var failCount = 0; @@ -53,7 +56,8 @@ export default function (path: string, columns: number, outDir: string) { convert([temp('_' + pixakiFileName + '_srgb.png'), '-transparent', 'blue', temp('_' + pixakiFileName + '_canvas.png')], () => { let layerSpritesheetPrintCount: number = 0, - visibleLayers = document.sprites[0].layers.filter((layer) => layer.isVisible); + visibleLayers = document.sprites[0].layers.filter((layer) => layer.isVisible), + animationDuration = Math.max.apply(Math, document.sprites[0].layers.map(function(o) { return o.clips.length; })); // Each layer document.sprites[0].layers.reverse().forEach((layer, layerIndex) => { @@ -71,18 +75,31 @@ export default function (path: string, columns: number, outDir: string) { return cel.identifier == clip.itemIdentifier; }); + // Examples for sanity: + // clipIndex is 0 and range start is 9, push 9 (9-0) + // clipIndex is 1 and range start is 9, push 8 (9-1) - (The original bug / had one valid item at the start) + // clipIndex is 5 and range start is 9, push 4 (9-5) + if(clipIndex !== clip.range.start){ + + for (var i = 0; i < clip.range.start - clipIndex; i++) { + celIDList.push('canvas'); + } + + } + let celImage: string = `${pixakiFilePath}/images/drawings/${cel.identifier}.png`; + // TODO: Don't perform all this if !cel.isVisible convert([temp('_' + pixakiFileName + '_canvas.png'), celImage, '-geometry', `+${cel.frame[0][0]}+${cel.frame[0][1]}`, '-composite', temp(`_${pixakiFileName}_${cel.identifier}.png`)], (error) => { - convert([temp(`_${pixakiFileName}_${cel.identifier}.png`), '-alpha', 'set', '-background', 'none', '-channel', 'A', '-evaluate', 'multiply', layer.opacity * cel.opacity, '+channel', temp(`_${pixakiFileName}_${cel.identifier}.png`)], (error) => { + convert([temp(`_${pixakiFileName}_${cel.identifier}.png`), '-alpha', 'set', '-background', 'none', '-channel', 'A', '-evaluate', 'multiply', cel.isVisible ? (layer.opacity * cel.opacity) : 0, '+channel', temp(`_${pixakiFileName}_${cel.identifier}.png`)], (error) => { celPrintCount++; if (celPrintCount == layer.clips.length) { - let column: number = layer.clips.length < columnCount ? layer.clips.length : columnCount, // max column wrap - row: number = Math.ceil(layer.clips.length / columnCount); // rows based on column wrap number + let column: number = animationDuration < columnCount ? animationDuration : columnCount, // max column wrap + row: number = Math.ceil(animationDuration / columnCount); // rows based on column wrap number let layerSpritesheet = temp(`_${pixakiFileName}_${layerIndex}_${layer.name.replace(" ", "-")}.png`); let grabLayerIndex = (layerName: string) => { @@ -90,56 +107,67 @@ export default function (path: string, columns: number, outDir: string) { } layerSpritesheets.push(layerSpritesheet); - - shell.exec(`montage ${temp(`_${pixakiFileName}_{${celIDList.join(',')}}.png`)} -tile ${column}x${row} -geometry ${size[0]}x${size[1]}+0+0 -background transparent ${layerSpritesheet}`, () => { + + // Factor in clip.range.start + exec(`montage ${temp(`_${pixakiFileName}_{${celIDList.join(',')}}.png`)} -tile ${column}x${row} -geometry ${size[0]}x${size[1]}+0+0 -background transparent ${layerSpritesheet}`, () => { layerSpritesheetPrintCount++; if (layerSpritesheetPrintCount == visibleLayers.length) { - let pages: string[] = []; + convert(['-size', `${row}x${column}`, 'canvas:blue', temp('_' + pixakiFileName + '_spritesheet_srgb.png')], () => { - layerSpritesheets.sort((a, b) => { return grabLayerIndex(a) - grabLayerIndex(b) }).reverse().forEach((spritesheetFile) => { - pages.push('-page', '+0+0', spritesheetFile); - }); + convert([temp('_' + pixakiFileName + '_srgb.png'), '-transparent', 'blue', temp('_' + pixakiFileName + '_spritesheet_canvas.png')], () => { + + let pages: string[] = []; + + pages.push('-page', '+0+0', temp('_' + pixakiFileName + '_spritesheet_canvas.png')); - let outFile: string = pixakiFilePath.replace('.pixaki', '.png'); // sprite.png, folder/sprite.png - let outFilePath: string = `${outDir}${outFile}`; // OUT_DIR/sprite.png, OUT_DIR/folder/sprite.png, sprite.png, folder/sprite.png - let outFolderPath: string = outFilePath.split(pixakiFileName)[0]; + layerSpritesheets.sort((a, b) => { return grabLayerIndex(a) - grabLayerIndex(b) }).reverse().forEach((spritesheetFile) => { + pages.push('-page', '+0+0', spritesheetFile); + }); - if (outFolderPath[outFolderPath.length - 1] == "/") { - outFolderPath = outFolderPath.slice(0, outFolderPath.length - 1); - } + let outFile: string = pixakiFilePath.replace('.pixaki', '.png'); // sprite.png, folder/sprite.png + let outFilePath: string = `${outDir}${outFile}`; // OUT_DIR/sprite.png, OUT_DIR/folder/sprite.png, sprite.png, folder/sprite.png + let outFolderPath: string = outFilePath.split(pixakiFileName)[0]; - if (outFolderPath != '') { - fs.mkdirSync(outFolderPath, { recursive: true }); - } + if (outFolderPath[outFolderPath.length - 1] == "/") { + outFolderPath = outFolderPath.slice(0, outFolderPath.length - 1); + } - convert(pages.concat(['-background', 'transparent', '-layers', 'merge', '+repage', `./${outFilePath}`]), (error) => { + if (outFolderPath != '') { + fs.mkdirSync(outFolderPath, { recursive: true }); + } - if (error) { - console.log(`\x1b[31m%s\x1b[0m ${outFilePath} (${error})`, 'x'); - failCount++; - } else { - console.log(`\x1b[32m%s\x1b[0m ${outFilePath}`, `✔️`); - successCount++; - } + convert(pages.concat(['-background', 'transparent', '-layers', 'merge', '+repage', `./${outFilePath}`]), (error) => { - globDoneCount++; + if (error) { + console.log(`\x1b[31m%s\x1b[0m ${outFilePath} (${error})`, 'x'); + failCount++; + } else { + console.log(`\x1b[32m%s\x1b[0m ${outFilePath}`, `✔️`); + successCount++; + } - if (globDoneCount == documentFiles.length) { + globDoneCount++; - DisplayCompleteMessage(successCount, failCount); - rimraf(TEMP_FOLDER_NAME, () => { }); - } + if (globDoneCount == documentFiles.length) { + + DisplayCompleteMessage(successCount, failCount); + // rimraf(TEMP_FOLDER_NAME, () => { }); + } + }); + }); }); } }); } }); }); - - celIDList.push(cel.identifier); + + if(true){ // cel.isVisible + celIDList.push(cel.identifier); + } }); } }); diff --git a/src/layer.ts b/src/layer.ts index 945100a..6a6751a 100644 --- a/src/layer.ts +++ b/src/layer.ts @@ -3,13 +3,13 @@ import { PixakiDocument } from "./interfaces"; import { convert } from 'imagemagick'; import { TEMP_FOLDER_NAME } from "./constants"; import { glob } from "glob"; +import { exec } from "shelljs"; export default function (path: string, layerName: string, columns: number, outDir: string) { console.log(`\nLayer exporting...`); var fs = require('fs'); - var shell = require('shelljs'); var rimraf = require('rimraf'); var outDir = outDir ? outDir + '/' : ''; var successCount = 0; @@ -28,6 +28,8 @@ export default function (path: string, layerName: string, columns: number, outDi if (!targetLayerName) { console.error("No layer arg given"); return; + }else{ + targetLayerName = targetLayerName.trim(); } // Pixaki 4 Document JSON file @@ -61,7 +63,7 @@ export default function (path: string, layerName: string, columns: number, outDi // Loop through layers to find layer matching the given target layer name (grab the ID) document.sprites[0].layers.forEach((layer: PixakiDocument['sprites'][0]['layers'][0]) => { - if (layer.name == targetLayerName) { + if (layer.name.trim() == targetLayerName) { // Sort by animation/frame (range.start) order and grab the itemIdentifier only layerIDs = layer.clips.sort((a: PixakiDocument['sprites'][0]['layers'][0]['clips'][0], b: PixakiDocument['sprites'][0]['layers'][0]['clips'][0]) => (a.range.start - b.range.start)).map((clip: any) => { return clip.itemIdentifier; }); return; @@ -107,7 +109,7 @@ export default function (path: string, layerName: string, columns: number, outDi fs.mkdirSync(outFolderPath, { recursive: true }); } - shell.exec(`montage ${temp(`_${pixakiFileName}_{${celIDList.join(',')}}.png`)} -tile ${column}x${row} -geometry ${size[0]}x${size[1]}+0+0 -background transparent './${outFilePath}'`, () => { + exec(`montage ${temp(`_${pixakiFileName}_{${celIDList.join(',')}}.png`)} -tile ${column}x${row} -geometry ${size[0]}x${size[1]}+0+0 -background transparent './${outFilePath}'`, () => { console.log(`\x1b[32m%s\x1b[0m ${outFilePath}`, `✔️`); diff --git a/src/package.json b/src/package.json index 84982f1..b65ddc2 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "pixaki", "description": "A CLI for Pixaki", - "version": "0.0.10", + "version": "0.0.11", "repository": { "type": "git", "url": "git://github.com/pixools/pixaki-cli.git"