summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Bache-Wiig <jens.bache-wiig@nokia.com>2010-10-18 17:52:35 +0200
committerJens Bache-Wiig <jens.bache-wiig@nokia.com>2010-10-18 17:52:35 +0200
commit9359df776b77abac95494034eb094ad76dd826eb (patch)
treee8c0338e0506bcd58cd621e7b0653b085560a7c4
First version
-rw-r--r--Export QML.jsx285
-rw-r--r--README.txt16
-rw-r--r--example.psdbin0 -> 588726 bytes
-rw-r--r--example_output/MyElement.qml118
-rw-r--r--example_output/images/background.pngbin0 -> 55513 bytes
-rw-r--r--example_output/images/background_text.pngbin0 -> 2990 bytes
-rw-r--r--example_output/images/drop_shadow.pngbin0 -> 1773 bytes
-rw-r--r--example_output/images/drop_shadow_1.pngbin0 -> 3241 bytes
-rw-r--r--example_output/images/drop_shadow_2.pngbin0 -> 5981 bytes
-rw-r--r--example_output/images/drop_shadow_3.pngbin0 -> 1996 bytes
-rw-r--r--example_output/images/mybutton.pngbin0 -> 1125 bytes
-rw-r--r--example_output/images/new_layer.pngbin0 -> 6890 bytes
-rw-r--r--example_output/images/new_layer_1.pngbin0 -> 311 bytes
-rw-r--r--example_output/images/new_layer_copy.pngbin0 -> 4842 bytes
-rw-r--r--example_output/images/new_layer_copy_1.pngbin0 -> 4868 bytes
-rw-r--r--example_output/images/new_layer_copy_2.pngbin0 -> 7899 bytes
-rw-r--r--example_output/images/qml.pngbin0 -> 858 bytes
17 files changed, 419 insertions, 0 deletions
diff --git a/Export QML.jsx b/Export QML.jsx
new file mode 100644
index 0000000..0b2403e
--- /dev/null
+++ b/Export QML.jsx
@@ -0,0 +1,285 @@
+/*
+Photoshop to QML Exporter
+
+Version: 0.1
+
+For information about Qt Quick itself:
+http://qt.nokia.com/products/qt-quick/
+
+Author: Jens Bache-wiig
+contact: jensbw@gmail.com
+
+Copyright (c) 2010, Nokia
+All rights reserved.
+
+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 runButton = 1;
+var cancelButton = 2;
+var qmlfile;
+
+
+// Setting keys
+var appString = "QML Exporter - 1"
+var outputNameKey = 0;
+var destinationKey = 1;
+var rasterizeKey = 2;
+
+main();
+
+// Converts SolidColor to a QML color property
+function qtColor(color) {
+ return "Qt.rgba(" + color.rgb.red + "," + color.rgb.green + "," + color.rgb.blue + ", 1.0)";
+}
+
+function main() {
+
+ var exportInfo = new Object();
+
+ if (cancelButton == setupDialog(exportInfo))
+ return 'cancel';
+
+ 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", "");
+ qmlfile = new File(outputName);
+ qmlfile.encoding = "UTF8";
+ qmlfile.open("w", "TEXT", "");
+ qmlfile.write("import Qt 4.7\n");
+ qmlfile.write("Rectangle {\n");
+ qmlfile.write(" width:" + app.activeDocument.width.as("px") + "\n");
+ qmlfile.write(" height:" + app.activeDocument.height.as("px") + "\n");
+ exportChildren(documentCopy, app.documents[documentName], exportInfo, documentCopy, exportInfo.fileNamePrefix);
+ documentCopy.close(SaveOptions.DONOTSAVECHANGES);
+ qmlfile.write("}\n");
+ qmlfile.close();
+}
+
+
+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.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 = 120
+ mainDialog.rasterizeText = mainDialog.groupFirstLine.add("checkbox", undefined, "Rasterize Text");
+
+ mainDialog.destinationFolder = mainDialog.groupSecondLine.add("edittext", undefined, "");
+ mainDialog.destinationFolder.preferredSize.width = 200;
+ mainDialog.buttonBrowse = mainDialog.groupSecondLine.add("button", undefined, "Browse..");
+
+ mainDialog.buttonBrowse.onClick = function () {
+ var defaultFolder = defaultFolder = "~";
+ var selFolder = Folder.selectDialog("Select destination", defaultFolder);
+ if (selFolder != null) mainDialog.destinationFolder.text = selFolder.fsName;
+ mainDialog.defaultElement.active = true;
+ }
+
+ mainDialog.buttonRun = mainDialog.groupThirdLine.add("button", undefined, "Export");
+ 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.groupThirdLine.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);
+ }
+ catch(e) { } // Use defaults
+
+ app.bringToFront();
+ 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);
+ app.putCustomOptions(appString, desc);
+ }
+
+ return result;
+}
+
+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) {
+ hideAll(dupObj)
+ for (var i = dupObj.artLayers.length - 1; i >= 0; i--) {
+ if (i < dupObj.artLayers.length - 1) dupObj.artLayers[i + 1].visible = false
+
+ var currentLayer = dupObj.artLayers[i];
+ currentLayer.visible = true
+
+ // 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.artLayers[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 empty space
+ if (activeDocument.activeLayer.isBackgroundLayer == false) {
+ app.activeDocument.trim(TrimType.TRANSPARENT);
+ }
+
+ fileNameBody = fileNameBody.replace(/[ :\/\\*\?\"\<\>\|#]/g, "_"); // '/\:*?"<>|' -> '_'
+ if (fileNameBody.length > 120) {
+ fileNameBody = fileNameBody.substring(0, 120);
+ }
+
+ var isText = (currentLayer.kind == LayerKind.TEXT && !(mainDialog.rasterizeText.value))
+
+ // Write QML properties
+ if (isText) qmlfile.write(" Text {\n");
+ else qmlfile.write(" Image {\n");
+ var filename = fileNameBody + ".png";
+ qmlfile.write(" id:" + fileNameBody + "\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;
+ dupObj.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
+ }
+
+ // Close tempfile
+ documentCopyTmp.close(SaveOptions.DONOTSAVECHANGES);
+ }
+
+ for (var i = 0; i < dupObj.layerSets.length; i++) {
+ var fileNameBody = fileNamePrefix;
+ fileNameBody += "_" + "s";
+ exportChildren(dupObj.layerSets[i], orgObj.layerSets[i], exportInfo, dupDocRef, fileNameBody); // recursive call
+ }
+}
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..0fb3c6c
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,16 @@
+Layers are exported as image and text elements in the root.qml file
+and png images are dumped into the "images" subirectory. Note that
+files may be replaced without warnings.
+
+Known issues:
+The font names are not really mapped accurately at the moment.
+
+Notes:
+The script has only been tested on Photoshop CS 4-5 and may or may not work on other versions.
+
+Warning:
+The software is provided as is and NO warranty is given. Use at your own risk.
+
+
+To install, just double click on the file or copy the script into your photoshop scripts directory.
+This is usually located in Photoshop_path\Presets\Scripts. \ No newline at end of file
diff --git a/example.psd b/example.psd
new file mode 100644
index 0000000..3251062
--- /dev/null
+++ b/example.psd
Binary files differ
diff --git a/example_output/MyElement.qml b/example_output/MyElement.qml
new file mode 100644
index 0000000..521db9b
--- /dev/null
+++ b/example_output/MyElement.qml
@@ -0,0 +1,118 @@
+import Qt 4.7
+Rectangle {
+ width:400
+ height:255
+ Image {
+ id:background
+ source:"images/background.png"
+ x:-2
+ y:0
+ opacity:1
+ }
+ Image {
+ id:new_layer_1
+ source:"images/new_layer_1.png"
+ x:1
+ y:64
+ opacity:0.2
+ }
+ Image {
+ id:new_layer
+ source:"images/new_layer.png"
+ x:63
+ y:161
+ opacity:1
+ }
+ Image {
+ id:new_layer_copy
+ source:"images/new_layer_copy.png"
+ x:136
+ y:12
+ opacity:1
+ }
+ Text {
+ id:push_me
+ text:"Push me"
+ font.pixelSize:22
+ font.family:"Tahoma"
+ color:Qt.rgba(255,255,255, 1.0)
+ smooth:true
+ x:164
+ y:17.5
+ opacity:1
+ }
+ Image {
+ id:drop_shadow_2
+ source:"images/drop_shadow_2.png"
+ x:22
+ y:75
+ opacity:0.3843137254902
+ }
+ Image {
+ id:background_text
+ source:"images/background_text.png"
+ x:24
+ y:77
+ opacity:1
+ }
+ Image {
+ id:drop_shadow_1
+ source:"images/drop_shadow_1.png"
+ x:296
+ y:158
+ opacity:0.8
+ }
+ Image {
+ id:mybutton
+ source:"images/mybutton.png"
+ x:309
+ y:168
+ opacity:1
+ }
+ Image {
+ id:new_layer_copy_1
+ source:"images/new_layer_copy_1.png"
+ x:116
+ y:145
+ opacity:0.63921568627451
+ }
+ Image {
+ id:drop_shadow
+ source:"images/drop_shadow.png"
+ x:139
+ y:112
+ opacity:0.8
+ }
+ Image {
+ id:new_layer_copy_2
+ source:"images/new_layer_copy_2.png"
+ x:159
+ y:121
+ opacity:0.63921568627451
+ }
+ Image {
+ id:drop_shadow_3
+ source:"images/drop_shadow_3.png"
+ x:315
+ y:194
+ opacity:0.57254901960784
+ }
+ Text {
+ id:button
+ text:"Button"
+ font.pixelSize:30
+ font.family:"Tahoma"
+ color:Qt.rgba(255,255,255, 1.0)
+ smooth:true
+ x:187
+ y:128.5
+ opacity:1
+ }
+ Image {
+ id:qml
+ source:"images/qml.png"
+ x:319
+ y:197
+ opacity:1
+ }
+}
diff --git a/example_output/images/background.png b/example_output/images/background.png
new file mode 100644
index 0000000..12e2dee
--- /dev/null
+++ b/example_output/images/background.png
Binary files differ
diff --git a/example_output/images/background_text.png b/example_output/images/background_text.png
new file mode 100644
index 0000000..c9abd58
--- /dev/null
+++ b/example_output/images/background_text.png
Binary files differ
diff --git a/example_output/images/drop_shadow.png b/example_output/images/drop_shadow.png
new file mode 100644
index 0000000..3b8c456
--- /dev/null
+++ b/example_output/images/drop_shadow.png
Binary files differ
diff --git a/example_output/images/drop_shadow_1.png b/example_output/images/drop_shadow_1.png
new file mode 100644
index 0000000..da946db
--- /dev/null
+++ b/example_output/images/drop_shadow_1.png
Binary files differ
diff --git a/example_output/images/drop_shadow_2.png b/example_output/images/drop_shadow_2.png
new file mode 100644
index 0000000..0e0a6b5
--- /dev/null
+++ b/example_output/images/drop_shadow_2.png
Binary files differ
diff --git a/example_output/images/drop_shadow_3.png b/example_output/images/drop_shadow_3.png
new file mode 100644
index 0000000..c738181
--- /dev/null
+++ b/example_output/images/drop_shadow_3.png
Binary files differ
diff --git a/example_output/images/mybutton.png b/example_output/images/mybutton.png
new file mode 100644
index 0000000..03bb59d
--- /dev/null
+++ b/example_output/images/mybutton.png
Binary files differ
diff --git a/example_output/images/new_layer.png b/example_output/images/new_layer.png
new file mode 100644
index 0000000..334baff
--- /dev/null
+++ b/example_output/images/new_layer.png
Binary files differ
diff --git a/example_output/images/new_layer_1.png b/example_output/images/new_layer_1.png
new file mode 100644
index 0000000..194002a
--- /dev/null
+++ b/example_output/images/new_layer_1.png
Binary files differ
diff --git a/example_output/images/new_layer_copy.png b/example_output/images/new_layer_copy.png
new file mode 100644
index 0000000..bb14ea0
--- /dev/null
+++ b/example_output/images/new_layer_copy.png
Binary files differ
diff --git a/example_output/images/new_layer_copy_1.png b/example_output/images/new_layer_copy_1.png
new file mode 100644
index 0000000..13c2d00
--- /dev/null
+++ b/example_output/images/new_layer_copy_1.png
Binary files differ
diff --git a/example_output/images/new_layer_copy_2.png b/example_output/images/new_layer_copy_2.png
new file mode 100644
index 0000000..2ed699f
--- /dev/null
+++ b/example_output/images/new_layer_copy_2.png
Binary files differ
diff --git a/example_output/images/qml.png b/example_output/images/qml.png
new file mode 100644
index 0000000..aa82e44
--- /dev/null
+++ b/example_output/images/qml.png
Binary files differ