Skip to content

Commit

Permalink
Fixes!
Browse files Browse the repository at this point in the history
- Files with empty first/bottom layers would result in greyscale export
- Add string trim to target layer name
- Fix cel visibility issue
- Fix issue whereby some layers only having some clips (I think only found on migrated Pixaki projects where layers can exist on one frame but not another)
  • Loading branch information
cjonasw committed May 1, 2021
1 parent 0966bc5 commit 6befc97
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 45 deletions.
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -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": "",
Expand All @@ -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",
Expand Down
98 changes: 63 additions & 35 deletions src/exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) => {
Expand All @@ -71,75 +75,99 @@ 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) => {
return parseInt(layerName.split(`_${pixakiFileName}_`)[1].split('_')[0]);
}

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);
}
});
}
});
Expand Down
8 changes: 5 additions & 3 deletions src/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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}`, `✔️`);

Expand Down
2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down

0 comments on commit 6befc97

Please sign in to comment.