123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /*
- Photoshop to QML Exporter
-
- Version: 0.4
-
- For information about Qt Quick itself:
- http://qt-project.org/doc/qt-5.0/qtquick/qtquick-index.html
-
- Author: Jens Bache-wiig
- contact: jens.bache-wiig@digia.com
-
- Copyright (c) 2013 Digia Plc and/or its subsidiary(-ies).
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by the <organization>.
- 4. Neither the name of the <organization> nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- #target photoshop
-
- var mainDialog
- var progressPanel
- var runButton = 1
- var cancelButton = 2
- var qmlfile
- var layerCount = 0
- var layerIndex = 0
- var cancelExport = 0
-
- // Setting keys
- var appString = "QML Exporter - 1"
- var outputNameKey = 0;
- var destinationKey = 1;
- var rasterizeKey = 2;
- var exportByGroupKey = 3;
- var exportHidden = 4;
- var exportQML = 5;
-
-
- Array.prototype.indexOf = function(elt /*, from*/)
- {
- var len = this.length;
-
- var from = Number(arguments[1]) || 0;
- from = (from < 0)
- ? Math.ceil(from)
- : Math.floor(from);
- if (from < 0)
- from += len;
-
- for (; from < len; from++)
- {
- if (from in this &&
- this[from] === elt)
- return from;
- }
- return -1;
- };
-
- main();
-
- function hexValue(dec)
- {
- var result;
- switch (dec) {
- case 10:
- result = "a";
- break;
- case 11:
- result = "b"
- break;
- case 12:
- result = "c";
- break;
- case 13:
- result = "d";
- break;
- case 14:
- result = "e"
- case 15:
- result = "f"
- break;
- default:
- result = dec
- break;
- }
- return result;
- }
-
- // Converts SolidColor to a QML color property
- function qtColor(color) {
- var r = Math.floor(color.rgb.red)
- var g = Math.floor(color.rgb.green);
- var b = Math.floor(color.rgb.blue)
- var a = Math.floor(color.rgb.alpha * 255)
- var v1 = hexValue(Math.floor(r / 16));
- var v2 = hexValue(r % 16);
- var v3 = hexValue(Math.floor(g / 16));
- var v4 = hexValue(g % 16);
- var v5 = hexValue(Math.floor(b / 16));
- var v6 = hexValue(b % 16);
- if (a > 0) {
- var v7 = hexValue(Math.floor(a / 16));
- var v8 = hexValue(a % 16);
- return "\"#" + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + "\"";
- }
- return "\"#" + v1 + v2 + v3 + v4 + v5 + v6 + "\"";
- }
-
- function main() {
-
- var exportInfo = new Object();
-
- if (cancelButton == setupDialog(exportInfo))
- return 'cancel';
-
-
- var myMaximumValue = 1.0;
- var myProgressBarWidth = 300;
- progressPanel = new Window('window', 'Exporting document to QML...');
- progressPanel.myProgressBar = progressPanel.add('progressbar', [12, 12, myProgressBarWidth, 24], 0, myMaximumValue);
- progressPanel.buttonCancel = progressPanel .add("button", undefined, "Cancel");
-
- progressPanel.buttonCancel.onClick = function () {
- cancelExport = true;
- progressPanel.hide();
- }
- progressPanel.show();
-
- app.preferences.rulerUnits = Units.PIXELS
-
- var documentName = app.activeDocument.name;
- app.activeDocument = app.documents[documentName];
- var documentCopy = app.activeDocument.duplicate();
- documentCopy.activeLayer = documentCopy.layers[documentCopy.layers.length - 1];
-
- var elementName = mainDialog.outputName.text;
- if (elementName.indexOf(".qml") == -1) // Append .qml unless not explicitly set
- elementName += ".qml"
-
- var outputName = exportInfo.destination + "/" + elementName;
-
- var imagefolder = new Folder(exportInfo.destination + "/images/");
- imagefolder.create();
-
- app.activeDocument.suspendHistory("export QML history", "");
-
- var exportQML = mainDialog.exportQML.value
-
- if (exportQML && !cancelExport) {
- qmlfile = new File(outputName);
- qmlfile.encoding = "UTF8";
- qmlfile.open("w", "TEXT", "");
- qmlfile.write("import Qt 4.7\n");
- qmlfile.write("Item {\n");
- qmlfile.write(" width:" + app.activeDocument.width.as("px") + "\n");
- qmlfile.write(" height:" + app.activeDocument.height.as("px") + "\n");
- }
-
- countLayers(documentCopy) // For progressBar
- exportChildren(documentCopy, app.documents[documentName], exportInfo, documentCopy, exportInfo.fileNamePrefix);
-
- if (exportQML) {
- documentCopy.close(SaveOptions.DONOTSAVECHANGES);
- qmlfile.write("}\n");
- qmlfile.close();
- }
- Panel.hide();
- }
-
-
- function setupDialog(exportInfo) {
- mainDialog = new Window("dialog", "Export Document To QML");
- var brush = mainDialog.graphics.newBrush(mainDialog.graphics.BrushType.THEME_COLOR, "appDialogBackground");
- mainDialog.graphics.backgroundColor = brush;
- mainDialog.graphics.disabledBackgroundColor = mainDialog.graphics.backgroundColor;
- mainDialog.orientation = 'column';
- mainDialog.alignChildren = 'left';
-
- mainDialog.groupFirstLine = mainDialog.add("group");
- mainDialog.groupFirstLine.orientation = 'row';
- mainDialog.groupFirstLine.alignChildren = 'left';
- mainDialog.groupFirstLine.alignment = 'fill';
-
- mainDialog.groupSecondLine = mainDialog.add("group");
- mainDialog.groupSecondLine.orientation = 'row';
- mainDialog.groupSecondLine.alignChildren = 'left';
-
- mainDialog.groupThirdLine = mainDialog.add("group");
- mainDialog.groupThirdLine.orientation = 'row';
- mainDialog.groupThirdLine.alignChildren = 'right';
- mainDialog.groupThirdLine.alignment = 'right';
-
- mainDialog.groupFourthLine = mainDialog.add("group");
- mainDialog.groupFourthLine.orientation = 'row';
- mainDialog.groupFourthLine.alignChildren = 'right';
- mainDialog.groupFourthLine.alignment = 'right';
-
- mainDialog.groupFirstLine.add("statictext", undefined, "Element Name:");
- mainDialog.groupSecondLine.add("statictext", undefined, "Output Folder:");
-
- mainDialog.outputName = mainDialog.groupFirstLine.add("edittext", undefined, "MyElement");
- mainDialog.outputName.preferredSize.width = 220
- mainDialog.rasterizeText = mainDialog.groupThirdLine.add("checkbox", undefined, "Rasterize Text");
- mainDialog.exportByGroup = mainDialog.groupThirdLine.add("checkbox", undefined, "Group layers");
- mainDialog.exportHidden = mainDialog.groupThirdLine.add("checkbox", undefined, "Export hidden");
-
- mainDialog.destinationFolder = mainDialog.groupSecondLine.add("edittext", undefined, "");
- mainDialog.destinationFolder.preferredSize.width = 220;
- mainDialog.buttonBrowse = mainDialog.groupSecondLine.add("button", undefined, "Browse..");
-
- mainDialog.exportQML = mainDialog.groupThirdLine.add("checkbox", undefined, "Export QML");
- mainDialog.buttonRun = mainDialog.groupFourthLine .add("button", undefined, "Export");
- mainDialog.defaultElement = mainDialog.buttonRun
-
- mainDialog.buttonBrowse.onClick = function () {
- var defaultFolder = defaultFolder = "~";
- var selFolder = Folder.selectDialog("Select destination", defaultFolder);
- if (selFolder != null)
- mainDialog.destinationFolder.text = selFolder.fsName;
- }
-
- mainDialog.buttonRun.onClick = function () {
- var destination = mainDialog.destinationFolder.text;
- if (destination.length == 0) {
- alert("you must specify a destination directory.");
- return;
- }
-
- var testFolder = new Folder(destination);
- if (!testFolder.exists) {
- alert("The destination directory does not exist.");
- return;
- }
- exportInfo.destination = destination;
- mainDialog.close(runButton);
- }
-
- mainDialog.buttonCancel = mainDialog.groupFourthLine .add("button", undefined, "Cancel");
- mainDialog.buttonCancel.onClick = function () {
- mainDialog.close(cancelButton);
- }
-
- try {
- // Try to read saved settings
- var desc = app.getCustomOptions(appString);
- mainDialog.outputName.text = desc.getString(outputNameKey);
- mainDialog.destinationFolder.text = desc.getString(destinationKey);
- mainDialog.rasterizeText.value = desc.getBoolean(rasterizeKey);
- mainDialog.exportByGroup.value = desc.getBoolean(exportByGroupKey);
- mainDialog.exportHidden.value = desc.getBoolean(exportHidden);
- mainDialog.exportQML.value = desc.getBoolean(exportQML);
- }
- catch(e) {
- // Default settings on first run
- mainDialog.exportByGroup.value = true;
- mainDialog.exportHidden.value = false;
- mainDialog.exportQML.value = true;
- } // Use defaults
-
- app.bringToFront();
- mainDialog.defaultElement.active = true;
- mainDialog.center();
-
- var result = mainDialog.show();
- if (cancelButton != result) {
- var desc = new ActionDescriptor();
- desc.putString(outputNameKey, mainDialog.outputName.text);
- desc.putString(destinationKey, mainDialog.destinationFolder.text);
- desc.putBoolean(rasterizeKey, mainDialog.rasterizeText.value);
- desc.putBoolean(exportByGroupKey, mainDialog.exportByGroup.value);
- desc.putBoolean(exportHidden, mainDialog.exportHidden.value);
- desc.putBoolean(exportQML, mainDialog.exportQML.value);
- app.putCustomOptions(appString, desc);
- }
- return result;
- }
-
- function countLayers(obj) {
- // Even when grouping layers, we export all layers at depth == 0
- for (var i = 0; i < obj.artLayers.length; i++) {
- layerCount++;
- }
- for (var i = 0; i < obj.layerSets.length; i++) { // Recursive
- if (!mainDialog.exportByGroup.value)
- countLayers(obj.layerSets[i]);
- layerCount++;
- }
- }
-
- function hideAll(obj) {
- for (var i = 0; i < obj.artLayers.length; i++) {
- obj.artLayers[i].allLocked = false;
- obj.artLayers[i].visible = false;
- }
- for (var i = 0; i < obj.layerSets.length; i++) { // Recursive
- hideAll(obj.layerSets[i]);
- }
- }
-
- function exportChildren(dupObj, orgObj, exportInfo, dupDocRef, fileNamePrefix) {
- var exportQML = mainDialog.exportQML.value
-
- // Track names to detect duplicates
- var names = new Array;
- var uniqueCounter = 1;
-
- if (!mainDialog.exportByGroup.value)
- hideAll(dupObj)
-
- for (var i = dupObj.layers.length - 1; i >= 0 && !cancelExport ; i--) {
- progressPanel.myProgressBar.value = (layerIndex++)/layerCount
- var currentLayer = dupObj.layers[i];
- // Ensure unique layer names
- while (names[currentLayer.name]) {
- $.writeln("Warning: duplicate layer name: " + currentLayer.name);
- currentLayer.name = orgObj.layers[i].name+ "_#" + uniqueCounter++;
- }
- names[currentLayer.name] = true;
-
- // Skip hidden layers
- var visible = true;
- if (!orgObj.layers[i].visible) {
- visible = false
- }
-
- if (!mainDialog.exportByGroup.value) {
- // Ignore layer groups and only show one layer at once
- if (currentLayer.typename== "LayerSet")
- continue;
- dupObj.layers[i].visible = true
- } else {
- // Hide all but current layergroup
- for (var k = dupObj.layers.length - 1; k >= 0; k--)
- dupObj.layers[k].visible = (k==i)
- }
-
- if (!visible && !mainDialog.exportHidden.value)
- continue;
-
- // Since we already save opacity, we dont want it affecting the output image
- var opacity = currentLayer.opacity / 100.0;
- currentLayer.opacity = 100;
-
- var layerName = dupObj.layers[i].name; // store layer name before change doc
- var fileNameBody = layerName.toLowerCase();
-
- // Ignore empty text layers
- if (currentLayer.kind == LayerKind.TEXT && currentLayer.textItem.contents == "") continue;
- var documentCopyTmp = dupDocRef.duplicate();
-
- // Trim copied document to layer bounds
- if (activeDocument.activeLayer.isBackgroundLayer == false) {
- // app.activeDocument.trim(TrimType.TRANSPARENT);
- var bounds = currentLayer.bounds
- activeDocument.crop (bounds, 0, bounds.width, bounds.height)
- }
-
- fileNameBody = fileNameBody.replace(/[ :\/\\*\?\"\<\>\|#]/g, "_"); // '/\:*?"<>|' -> '_'
- if (fileNameBody.length > 120) {
- fileNameBody = fileNameBody.substring(0, 120);
- }
-
- var isText = (currentLayer.kind == LayerKind.TEXT && !(mainDialog.rasterizeText.value))
- var filename = fileNameBody + ".png";
- if (exportQML) {
- // Write QML properties
- if (isText) qmlfile.write(" Text {\n");
- else qmlfile.write(" Image {\n");
- qmlfile.write(" id: " + fileNameBody + "\n");
-
- if (!visible)
- qmlfile.write(" visible: " + visible+ "\n");
-
- var xoffset = currentLayer.bounds[0].as("px");
- var yoffset = currentLayer.bounds[1].as("px");
-
- if (isText) {
- var textItem = currentLayer.textItem;
- qmlfile.write(" text: \"" + textItem.contents + "\"\n");
-
- // ### Temporary hack to set font positioning
- // Using pointsize doesnt work for some reason and we need to
- // figure out which metric we need to use ascending, perhaps?
- yoffset -= textItem.size.as("px") / 4;
-
- qmlfile.write(" font.pixelSize: " + Math.floor(textItem.size.as("px")) + "\n");
-
- //var fontfamily = app.textFonts.getByName(textitem.font);
- qmlfile.write(" font.family: \"" + textItem.font + "\"\n");
-
- if (textItem.font.indexOf("Bold") != -1) qmlfile.write(" font.bold: true\n");
-
- if (textItem.font.indexOf("Italic") != -1) qmlfile.write(" font.italic: true\n");
- qmlfile.write(" color: " + qtColor(currentLayer.textItem.color) + "\n");
- qmlfile.write(" smooth: true\n");
- } else {
- qmlfile.write(" source: \"images/" + filename + "\"\n");
- }
-
- qmlfile.write(" x: " + xoffset + "\n");
- qmlfile.write(" y: " + yoffset + "\n");
- qmlfile.write(" opacity: " + opacity + "\n");
- qmlfile.write(" }\n");
- }
- // Save document
- if (!isText) {
- var saveFile = new File(exportInfo.destination + "/images/" + filename);
- pngSaveOptions = new PNGSaveOptions();
- pngSaveOptions.interlaced = false;
- documentCopyTmp.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
- }
-
- // Close tempfile
- documentCopyTmp.close(SaveOptions.DONOTSAVECHANGES);
-
- if (!mainDialog.exportByGroup.value)
- dupObj.layers[i].visible = false
- }
-
- for (var i = 0; i < dupObj.layerSets.length; i++) {
- var fileNameBody = fileNamePrefix;
- fileNameBody += "_" + "s";
- if (!mainDialog.exportByGroup.value)
- exportChildren(dupObj.layerSets[i], orgObj.layerSets[i], exportInfo, dupDocRef, fileNameBody); // recursive call
- }
- }
-
- function collectLayerSets (theParent) {
- if (!allLayerSets) {
- var allLayerSets = new Array
- }
- for (var m = theParent.layers.length - 1; m >= 0;m--) {
- var theLayer = theParent.layers[m];
- // No need to process hidden layers
- if (theLayer.typename == "LayerSet") {
- allLayerSets = allLayerSets.concat(theLayer);
- allLayerSets = allLayerSets.concat(collectLayerSets(theLayer))
- }
- }
- return allLayerSets
- };
|