Created
September 11, 2012 11:52
-
-
Save shiwano/3697844 to your computer and use it in GitHub Desktop.
Generate a sprite from animation frames
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
<javascriptresource> | |
<name>Generate a sprite from animation frames</name> | |
<category>web</category> | |
</javascriptresource> | |
*/ | |
var AnimationSpriteGenerator, console, main, showInputSizeDialog; | |
console = { | |
log: function(string) { | |
return $.writeln(string); | |
} | |
}; | |
AnimationSpriteGenerator = (function() { | |
function AnimationSpriteGenerator(psdDir, width, height) { | |
this.psdDir = psdDir; | |
this.psdFiles = new Folder(psdDir).getFiles('*.psd'); | |
this.width = width; | |
this.height = height; | |
} | |
AnimationSpriteGenerator.prototype.revert = function() { | |
var idRvrt; | |
idRvrt = charIDToTypeID("Rvrt"); | |
return executeAction(idRvrt, void 0, DialogModes.NO); | |
}; | |
AnimationSpriteGenerator.prototype.changeAnimationFrame = function(index) { | |
var desc66, idanimationFrameClass, idnull, idslct, ref52; | |
idslct = charIDToTypeID("slct"); | |
desc66 = new ActionDescriptor(); | |
idnull = charIDToTypeID("null"); | |
ref52 = new ActionReference(); | |
idanimationFrameClass = stringIDToTypeID("animationFrameClass"); | |
ref52.putIndex(idanimationFrameClass, index); | |
desc66.putReference(idnull, ref52); | |
return executeAction(idslct, desc66, DialogModes.NO); | |
}; | |
AnimationSpriteGenerator.prototype.getAnimationLength = function() { | |
var count; | |
count = 1; | |
while (true) { | |
try { | |
this.changeAnimationFrame(count); | |
} catch (error) { | |
break; | |
} | |
count += 1; | |
} | |
return count; | |
}; | |
AnimationSpriteGenerator.prototype.save = function() { | |
var file, options; | |
app.activeDocument = this.spriteDocument; | |
file = new File(this.activeDocument.fullName + '.png'); | |
options = new PNGSaveOptions(); | |
options.interlaced = false; | |
this.spriteDocument.saveAs(file, options, true, Extension.LOWERCASE); | |
return app.activeDocument = this.activeDocument; | |
}; | |
AnimationSpriteGenerator.prototype.formSpriteLayerPosition = function(animationIndex) { | |
var layer; | |
app.activeDocument = this.spriteDocument; | |
layer = this.spriteDocument.artLayers.getByName("" + animationIndex + " frame"); | |
layer.translate(this.width * (animationIndex - 1), 0); | |
return app.activeDocument = this.activeDocument; | |
}; | |
AnimationSpriteGenerator.prototype.getVisibleArtLayers = function(result, layers) { | |
var layer, _i, _len; | |
if (result == null) { | |
result = []; | |
} | |
if (layers == null) { | |
layers = this.activeDocument.layers; | |
} | |
for (_i = 0, _len = layers.length; _i < _len; _i++) { | |
layer = layers[_i]; | |
if (layer.isBackgroundLayer || !layer.visible) { | |
continue; | |
} | |
switch (layer.typename) { | |
case 'LayerSet': | |
this.getVisibleArtLayers(result, layer.artLayers); | |
break; | |
case 'ArtLayer': | |
result.push(layer); | |
} | |
} | |
return result; | |
}; | |
AnimationSpriteGenerator.prototype.mergeVisibleLayers = function() { | |
var artLayers; | |
artLayers = this.getVisibleArtLayers(); | |
if (artLayers.length > 0) { | |
this.activeDocument.activeLayer = artLayers[0]; | |
} | |
if (artLayers.length > 1) { | |
return this.activeDocument.mergeVisibleLayers(); | |
} | |
}; | |
AnimationSpriteGenerator.prototype.duplicateAnimationFrameToSprite = function(animationIndex) { | |
this.activeDocument.resizeImage(this.width, this.height); | |
this.changeAnimationFrame(animationIndex); | |
this.mergeVisibleLayers(); | |
this.activeDocument.activeLayer.name = "" + animationIndex + " frame"; | |
this.activeDocument.activeLayer.duplicate(this.spriteDocument.activeLayer, ElementPlacement.PLACEAFTER); | |
this.formSpriteLayerPosition(animationIndex); | |
return this.revert(); | |
}; | |
AnimationSpriteGenerator.prototype.duplicateAnimationFrames = function(file) { | |
var animationIndex, animationLength, _i; | |
this.activeDocument = open(file); | |
animationLength = this.getAnimationLength(); | |
if (animationLength === 1) { | |
return; | |
} | |
this.spriteDocument = documents.add(this.width * (animationLength - 1), this.height, 72, 'sprite', NewDocumentMode.RGB, DocumentFill.TRANSPARENT); | |
app.activeDocument = this.activeDocument; | |
for (animationIndex = _i = 1; 1 <= animationLength ? _i < animationLength : _i > animationLength; animationIndex = 1 <= animationLength ? ++_i : --_i) { | |
this.duplicateAnimationFrameToSprite(animationIndex); | |
} | |
this.save(); | |
this.activeDocument.close(SaveOptions.DONOTSAVECHANGES); | |
return this.spriteDocument.close(SaveOptions.DONOTSAVECHANGES); | |
}; | |
AnimationSpriteGenerator.prototype.run = function() { | |
var file, _i, _len, _ref, _results; | |
_ref = this.psdFiles; | |
_results = []; | |
for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
file = _ref[_i]; | |
_results.push(this.duplicateAnimationFrames(file)); | |
} | |
return _results; | |
}; | |
return AnimationSpriteGenerator; | |
})(); | |
showInputSizeDialog = function(message, defaultSize) { | |
var dialog, size; | |
if (defaultSize == null) { | |
defaultSize = 100; | |
} | |
dialog = new Window("dialog", message); | |
dialog.bounds = [400, 400, 600, 500]; | |
dialog.cancelButton = dialog.add("button", [40, 60, 110, 60 + 25], "Cancel", { | |
name: "cancel" | |
}); | |
dialog.okButton = dialog.add("button", [120, 60, 170, 60 + 25], "OK", { | |
name: "ok" | |
}); | |
dialog.sizeText = dialog.add("edittext", [10, 10, 110, 10 + 25], defaultSize); | |
if (dialog.show() === 1) { | |
size = dialog.sizeText.text; | |
} | |
size = Number(size); | |
if (isNaN(size) || size <= 0) { | |
throw Error('Invalid size'); | |
} | |
return size; | |
}; | |
main = function() { | |
var height, psdDir, width; | |
width = showInputSizeDialog('Input width'); | |
height = showInputSizeDialog('Input height'); | |
psdDir = Folder.selectDialog('Choose PSD file directory'); | |
return new AnimationSpriteGenerator(psdDir, width, height).run(); | |
}; | |
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### | |
<javascriptresource> | |
<name>Generate a sprite from animation frames</name> | |
<category>web</category> | |
</javascriptresource> | |
### | |
# console.log | |
console = log: (string) -> $.writeln string | |
class AnimationSpriteGenerator | |
constructor: (psdDir, width, height) -> | |
@psdDir = psdDir | |
@psdFiles = new Folder(psdDir).getFiles('*.psd') | |
@width = width | |
@height = height | |
# 「ファイル -> 復帰」 | |
revert: -> | |
idRvrt = charIDToTypeID( "Rvrt" ) | |
executeAction(idRvrt, undefined, DialogModes.NO) | |
# アニメーションフレームの切り替え | |
changeAnimationFrame: (index) -> | |
idslct = charIDToTypeID("slct") | |
desc66 = new ActionDescriptor() | |
idnull = charIDToTypeID("null") | |
ref52 = new ActionReference() | |
idanimationFrameClass = stringIDToTypeID("animationFrameClass") | |
ref52.putIndex idanimationFrameClass, index | |
desc66.putReference idnull, ref52 | |
executeAction idslct, desc66, DialogModes.NO | |
# アニメーションフレームの最大数を返す(APIがなかったので力技) | |
getAnimationLength: -> | |
count = 1 | |
while true | |
try | |
@changeAnimationFrame count | |
catch error | |
break | |
count += 1 | |
count | |
save: -> | |
app.activeDocument = @spriteDocument | |
file = new File(@activeDocument.fullName + '.png') | |
options = new PNGSaveOptions() | |
options.interlaced = false | |
@spriteDocument.saveAs(file, options, true, Extension.LOWERCASE) | |
app.activeDocument = @activeDocument | |
formSpriteLayerPosition: (animationIndex) -> | |
app.activeDocument = @spriteDocument | |
layer = @spriteDocument.artLayers.getByName "#{animationIndex} frame" | |
layer.translate @width * (animationIndex - 1), 0 | |
app.activeDocument = @activeDocument | |
getVisibleArtLayers: (result = [], layers = @activeDocument.layers) -> | |
for layer in layers | |
continue if layer.isBackgroundLayer or not layer.visible | |
switch layer.typename | |
when 'LayerSet' | |
@getVisibleArtLayers result, layer.artLayers | |
when 'ArtLayer' | |
result.push layer | |
result | |
mergeVisibleLayers: -> | |
artLayers = @getVisibleArtLayers() | |
@activeDocument.activeLayer = artLayers[0] if artLayers.length > 0 | |
@activeDocument.mergeVisibleLayers() if artLayers.length > 1 | |
duplicateAnimationFrameToSprite: (animationIndex) -> | |
@activeDocument.resizeImage @width, @height | |
@changeAnimationFrame animationIndex | |
@mergeVisibleLayers() | |
@activeDocument.activeLayer.name = "#{animationIndex} frame" | |
@activeDocument.activeLayer.duplicate @spriteDocument.activeLayer, | |
ElementPlacement.PLACEAFTER | |
@formSpriteLayerPosition animationIndex | |
@revert() | |
duplicateAnimationFrames: (file) -> | |
@activeDocument = open(file) | |
animationLength = @getAnimationLength() | |
return if animationLength is 1 | |
@spriteDocument = documents.add @width * (animationLength - 1), @height, | |
72, 'sprite', NewDocumentMode.RGB, DocumentFill.TRANSPARENT | |
app.activeDocument = @activeDocument | |
for animationIndex in [1...animationLength] | |
@duplicateAnimationFrameToSprite(animationIndex) | |
@save() | |
@activeDocument.close(SaveOptions.DONOTSAVECHANGES) | |
@spriteDocument.close(SaveOptions.DONOTSAVECHANGES) | |
run: -> | |
for file in @psdFiles | |
@duplicateAnimationFrames file | |
showInputSizeDialog = (message, defaultSize = 100) -> | |
dialog = new Window("dialog", message) | |
dialog.bounds = [400, 400, 600, 500] | |
dialog.cancelButton = dialog.add "button", [40, 60, 110, 60 + 25], "Cancel", | |
name: "cancel" | |
dialog.okButton = dialog.add "button", [120, 60, 170, 60 + 25], "OK", | |
name: "ok" | |
dialog.sizeText = dialog.add "edittext", [10, 10, 110, 10 + 25], defaultSize | |
size = dialog.sizeText.text if dialog.show() is 1 | |
size = Number size | |
if isNaN(size) or size <= 0 | |
throw Error 'Invalid size' | |
size | |
main = -> | |
width = showInputSizeDialog 'Input width' | |
height = showInputSizeDialog 'Input height' | |
psdDir = Folder.selectDialog 'Choose PSD file directory' | |
new AnimationSpriteGenerator(psdDir, width, height).run() | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment