Adobe Animate

From bernie's
Jump to navigation Jump to search

Export layers to single swf file for AE

/!\ Make sure in the publish settings, swf > advanced settings > "Include hiden layers" is turned OFF before launching the jsfl file

/*
 * JSFL Script to export each layer of an Adobe Animate FLA file main timeline (no sub-symbols). 
 * as a separate SWF file, using padded layer number + layer name as the output filename.
 * Some error checking.
 * Hidden and guide layers will be skipped. Masks should be broken to filled shapes.
 */

// Check if a document is open
if (fl.getDocumentDOM() == null) {
    fl.trace('Error: Please open an Adobe Animate (FLA) file.');
} else {
    var dom = fl.getDocumentDOM();
    var timeline = dom.getTimeline();
    
	//
	var dom = fl.getDocumentDOM();

	//patch to toogle off invisible layers in publish settings stolen from https://community.adobe.com/t5/animate-discussions/toggle-options-in-publish-settings-with-javascript-code/td-p/9673165
	var profileXML = dom.exportPublishProfileString(dom.currentPublishProfile);
	// WARNING: This is a hack that does direct string manipulation instead of properly parsing the XML
	// exclude hidden layers (Flash)
	profileXML = profileXML.replace(/<InvisibleLayer>.<\/InvisibleLayer>/g, '<InvisibleLayer>0</InvisibleLayer>');
	// exclude hidden layers (HTML/SVG)
	profileXML = profileXML.replace(/<Property name="includeHiddenLayers">.+?<\/Property>/g, '<Property name="includeHiddenLayers">false</Property>');
	// JPEG quality
	profileXML = profileXML.replace(/<Quality>.+?<\/Quality>/g, '<Quality>100</Quality>');
	// apply updated profile
	dom.importPublishProfileString(profileXML);

	
    // Get document path and file name (without extension)
    var flaPath = dom.path;
    var flaName = dom.name.substring(0, dom.name.lastIndexOf('.'));
	var flaFolder = flaPath.match(/(.*)[\/\\]/)[1]||'';
	
	//horrible flash oddity. Barf. tested on windows, not macos
	var flaFolderURI = 'file:///' + flaFolder.replace(/\\/g, '/').split(':').join('|').split(' ').join('%20');
    
    // Construct the path for the 'export' folder
    // The folder will be next to the FLA file
    var exportFolderPath = flaFolderURI + '/EXPORT';
	
	// Create folder if it doesn't exists. Error out if it doesn't work.
	if(!FLfile.exists(exportFolderPath) && !FLfile.createFolder(exportFolderPath)){
		throw new Error('Cannot write folder: '+exportFolderPath);
	}else{
		fl.trace(' --- Exporting to ' + flaFolder + '/EXPORT');
	}

    // Array of all layers in the current timeline
    var layers = timeline.layers;
    var totalLayers = layers.length;
    
    // Determine padding length (e.g., 2 for up to 99 layers, 3 for up to 999, 2 minimum)
    var paddingLength = Math.max(2,totalLayers.toString().length);

	
	// Let's store the visibility of each layer, then hide all of them. Skip visibility of mask layers.
	var layersVisibility = {};
	var layersMask = {};
    for (var i = 0; i < totalLayers; i++) {
		var currentLayer = layers[i];  
		layersVisibility[i] = currentLayer.visible;
		if(currentLayer.layerType == "mask"){
			layersMask[i] = true;
		}else{
			currentLayer.visible = false;
			layersMask[i] = false;
		}

	}

    // Loop through all layers
    for (var i = 0; i < totalLayers; i++) {
        var currentLayer = layers[i];  
        
		// Only proceed if: 
		//	- layer is initially visible
		//	- layer is not a guide layer
		//  - layer is not a locked masked layer
		
		if(layersVisibility[i] && currentLayer.layerType != 'guide'){
			//fl.trace(currentLayer.parentLayer)
			// Make only the current layer visible
			currentLayer.visible = true;
			
			// --- 2. Filename Construction ---
			
			// Calculate layer index (1-based). padStart doesn't seem to work, here's a workaround for padding, hopefully your file should have less than 10000 layers....
			var layerIndex = i + 1;
			layerIndex =  "00000"+layerIndex.toString();
			layerIndex = layerIndex.slice(-paddingLength);

			// Clean up the layer name to be file-system friendly (remove spaces and special chars)
			// Replacing non-alphanumeric/hyphen/underscore with an underscore
			var cleanLayerName = currentLayer.name.replace(/[^a-zA-Z0-9_-]/g, '_');
			
			// Construct the full output filename
			var outputFileName = layerIndex + '_' + cleanLayerName + '.swf';
			var outputFilePath = exportFolderPath + '/' +outputFileName;
			
			// --- 3. Export ---
			
			// Export the current frame/selection as SWF
			// The exportSWF method exports based on the current visible state of the layers
			var success = dom.exportSWF(outputFilePath, false); // 'false' means export all frames, which is usually correct for layer-based export
			
			if (success) {
				fl.trace("✅ Exported: " + outputFileName);
			} else {
				fl.trace("❌ Failed to export: " + outputFileName);
			}
			
			//re-hide layer
			currentLayer.visible = false;
		}
    }

    // --- 4. Cleanup ---
    
    // Restore all layers to be visible at the end
    for (var i = 0; i < totalLayers; i++) {
        timeline.layers[i].visible = layersVisibility[i];
    }

    // Select the first frame and first layer for a clean exit state
    timeline.currentFrame = 0;
    timeline.currentLayer = 0;
    
    fl.trace("--- Layer Export Complete! ---");
}