Browse Source

second commit

Pauline Berta 3 months ago
parent
commit
23ed6d93c1
1 changed files with 463 additions and 0 deletions
  1. 463
    0
      Script (Conversion .PSD vers .QML)/Export QML.jsx

+ 463
- 0
Script (Conversion .PSD vers .QML)/Export QML.jsx View File

@@ -0,0 +1,463 @@
1
+/*
2
+Photoshop to QML Exporter
3
+
4
+Version: 0.4
5
+
6
+For information about Qt Quick itself:
7
+http://qt-project.org/doc/qt-5.0/qtquick/qtquick-index.html
8
+
9
+Author: Jens Bache-wiig
10
+contact: jens.bache-wiig@digia.com
11
+
12
+Copyright (c) 2013 Digia Plc and/or its subsidiary(-ies).
13
+
14
+Redistribution and use in source and binary forms, with or without
15
+modification, are permitted provided that the following conditions are met:
16
+1. Redistributions of source code must retain the above copyright
17
+   notice, this list of conditions and the following disclaimer.
18
+2. Redistributions in binary form must reproduce the above copyright
19
+   notice, this list of conditions and the following disclaimer in the
20
+   documentation and/or other materials provided with the distribution.
21
+3. All advertising materials mentioning features or use of this software
22
+   must display the following acknowledgement:
23
+   This product includes software developed by the <organization>.
24
+4. Neither the name of the <organization> nor the
25
+   names of its contributors may be used to endorse or promote products
26
+   derived from this software without specific prior written permission.
27
+
28
+THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY
29
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
32
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
+*/
39
+
40
+#target photoshop
41
+
42
+var mainDialog
43
+var progressPanel
44
+var runButton = 1
45
+var cancelButton = 2
46
+var qmlfile
47
+var layerCount = 0
48
+var layerIndex = 0
49
+var cancelExport = 0
50
+
51
+// Setting keys
52
+var appString = "QML Exporter - 1"
53
+var outputNameKey = 0;
54
+var destinationKey = 1;
55
+var rasterizeKey = 2;
56
+var exportByGroupKey = 3;
57
+var exportHidden = 4;
58
+var exportQML = 5;
59
+
60
+
61
+Array.prototype.indexOf = function(elt /*, from*/)
62
+{
63
+    var len = this.length;
64
+
65
+    var from = Number(arguments[1]) || 0;
66
+    from = (from < 0)
67
+            ? Math.ceil(from)
68
+            : Math.floor(from);
69
+    if (from < 0)
70
+        from += len;
71
+
72
+    for (; from < len; from++)
73
+    {
74
+        if (from in this &&
75
+                this[from] === elt)
76
+            return from;
77
+    }
78
+    return -1;
79
+};
80
+
81
+main();
82
+
83
+function hexValue(dec)
84
+{
85
+    var result;
86
+    switch (dec) {
87
+    case 10:
88
+        result = "a";
89
+        break;
90
+    case 11:
91
+        result = "b"
92
+        break;
93
+    case 12:
94
+        result = "c";
95
+        break;
96
+    case 13:
97
+        result = "d";
98
+        break;
99
+    case 14:
100
+        result = "e"
101
+    case 15:
102
+        result = "f"
103
+        break;
104
+    default:
105
+        result = dec
106
+        break;
107
+    }
108
+    return result;
109
+}
110
+
111
+// Converts SolidColor to a QML color property
112
+function qtColor(color) {
113
+    var r = Math.floor(color.rgb.red)
114
+    var g = Math.floor(color.rgb.green);
115
+    var b = Math.floor(color.rgb.blue)
116
+    var a = Math.floor(color.rgb.alpha * 255)
117
+    var v1 = hexValue(Math.floor(r / 16));
118
+    var v2 = hexValue(r % 16);
119
+    var v3 = hexValue(Math.floor(g / 16));
120
+    var v4 = hexValue(g % 16);
121
+    var v5 = hexValue(Math.floor(b / 16));
122
+    var v6 = hexValue(b % 16);
123
+    if (a > 0) {
124
+        var v7 = hexValue(Math.floor(a / 16));
125
+        var v8 = hexValue(a % 16);
126
+        return  "\"#" + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + "\"";
127
+    }
128
+    return  "\"#" + v1 + v2 + v3 + v4 + v5 + v6 + "\"";
129
+}
130
+
131
+function main() {
132
+
133
+    var exportInfo = new Object();
134
+
135
+    if (cancelButton == setupDialog(exportInfo)) 
136
+        return 'cancel';
137
+
138
+
139
+    var myMaximumValue = 1.0;
140
+    var myProgressBarWidth = 300;
141
+    progressPanel = new Window('window', 'Exporting document to QML...');
142
+    progressPanel.myProgressBar = progressPanel.add('progressbar', [12, 12, myProgressBarWidth, 24], 0, myMaximumValue);
143
+    progressPanel.buttonCancel = progressPanel .add("button", undefined, "Cancel");
144
+
145
+    progressPanel.buttonCancel.onClick = function () {
146
+          cancelExport = true;
147
+          progressPanel.hide();
148
+    }
149
+    progressPanel.show();
150
+
151
+   app.preferences.rulerUnits = Units.PIXELS
152
+
153
+    var documentName = app.activeDocument.name;
154
+    app.activeDocument = app.documents[documentName];
155
+    var documentCopy = app.activeDocument.duplicate();
156
+    documentCopy.activeLayer = documentCopy.layers[documentCopy.layers.length - 1];
157
+
158
+    var elementName = mainDialog.outputName.text;
159
+    if (elementName.indexOf(".qml") == -1) 	// Append .qml unless not explicitly set
160
+        elementName += ".qml"
161
+
162
+    var outputName = exportInfo.destination + "/" + elementName;
163
+
164
+    var imagefolder = new Folder(exportInfo.destination + "/images/");
165
+    imagefolder.create();
166
+
167
+    app.activeDocument.suspendHistory("export QML history", "");
168
+    
169
+    var exportQML = mainDialog.exportQML.value
170
+
171
+    if (exportQML && !cancelExport) {
172
+        qmlfile = new File(outputName);
173
+        qmlfile.encoding = "UTF8";
174
+        qmlfile.open("w", "TEXT", "");
175
+        qmlfile.write("import Qt 4.7\n");
176
+        qmlfile.write("Item {\n");
177
+        qmlfile.write("    width:" + app.activeDocument.width.as("px") + "\n");
178
+        qmlfile.write("    height:" + app.activeDocument.height.as("px") + "\n");
179
+    }
180
+
181
+    countLayers(documentCopy) // For progressBar
182
+    exportChildren(documentCopy, app.documents[documentName], exportInfo, documentCopy, exportInfo.fileNamePrefix);
183
+
184
+    if (exportQML) {
185
+        documentCopy.close(SaveOptions.DONOTSAVECHANGES);
186
+        qmlfile.write("}\n");
187
+        qmlfile.close();
188
+    }
189
+    Panel.hide();
190
+}
191
+
192
+
193
+function setupDialog(exportInfo) {
194
+    mainDialog = new Window("dialog", "Export Document To QML");
195
+    var brush = mainDialog.graphics.newBrush(mainDialog.graphics.BrushType.THEME_COLOR, "appDialogBackground");
196
+    mainDialog.graphics.backgroundColor = brush;
197
+    mainDialog.graphics.disabledBackgroundColor = mainDialog.graphics.backgroundColor;
198
+    mainDialog.orientation = 'column';
199
+    mainDialog.alignChildren = 'left';
200
+
201
+    mainDialog.groupFirstLine = mainDialog.add("group");
202
+    mainDialog.groupFirstLine.orientation = 'row';
203
+    mainDialog.groupFirstLine.alignChildren = 'left';
204
+    mainDialog.groupFirstLine.alignment = 'fill';
205
+
206
+    mainDialog.groupSecondLine = mainDialog.add("group");
207
+    mainDialog.groupSecondLine.orientation = 'row';
208
+    mainDialog.groupSecondLine.alignChildren = 'left';
209
+
210
+    mainDialog.groupThirdLine = mainDialog.add("group");
211
+    mainDialog.groupThirdLine.orientation = 'row';
212
+    mainDialog.groupThirdLine.alignChildren = 'right';
213
+    mainDialog.groupThirdLine.alignment = 'right';
214
+
215
+    mainDialog.groupFourthLine = mainDialog.add("group");
216
+    mainDialog.groupFourthLine.orientation = 'row';
217
+    mainDialog.groupFourthLine.alignChildren = 'right';
218
+    mainDialog.groupFourthLine.alignment = 'right';
219
+
220
+    mainDialog.groupFirstLine.add("statictext", undefined, "Element Name:");
221
+    mainDialog.groupSecondLine.add("statictext", undefined, "Output Folder:");
222
+
223
+    mainDialog.outputName = mainDialog.groupFirstLine.add("edittext", undefined, "MyElement");
224
+    mainDialog.outputName.preferredSize.width = 220
225
+    mainDialog.rasterizeText = mainDialog.groupThirdLine.add("checkbox", undefined, "Rasterize Text");
226
+    mainDialog.exportByGroup = mainDialog.groupThirdLine.add("checkbox", undefined, "Group layers");
227
+    mainDialog.exportHidden = mainDialog.groupThirdLine.add("checkbox", undefined, "Export hidden");
228
+
229
+    mainDialog.destinationFolder = mainDialog.groupSecondLine.add("edittext", undefined, "");
230
+    mainDialog.destinationFolder.preferredSize.width = 220;
231
+    mainDialog.buttonBrowse = mainDialog.groupSecondLine.add("button", undefined, "Browse..");
232
+    
233
+    mainDialog.exportQML = mainDialog.groupThirdLine.add("checkbox", undefined, "Export QML");
234
+    mainDialog.buttonRun = mainDialog.groupFourthLine .add("button", undefined, "Export");
235
+    mainDialog.defaultElement = mainDialog.buttonRun 
236
+    
237
+    mainDialog.buttonBrowse.onClick = function () {
238
+        var defaultFolder = defaultFolder = "~";
239
+        var selFolder = Folder.selectDialog("Select destination", defaultFolder);
240
+        if (selFolder != null) 
241
+            mainDialog.destinationFolder.text = selFolder.fsName;
242
+    }
243
+
244
+    mainDialog.buttonRun.onClick = function () {
245
+        var destination = mainDialog.destinationFolder.text;
246
+        if (destination.length == 0) {
247
+            alert("you must specify a destination directory.");
248
+            return;
249
+        }
250
+
251
+        var testFolder = new Folder(destination);
252
+        if (!testFolder.exists) {
253
+            alert("The destination directory does not exist.");
254
+            return;
255
+        }
256
+        exportInfo.destination = destination;
257
+        mainDialog.close(runButton);
258
+     }
259
+
260
+      mainDialog.buttonCancel = mainDialog.groupFourthLine .add("button", undefined, "Cancel");
261
+      mainDialog.buttonCancel.onClick = function () {
262
+        mainDialog.close(cancelButton);
263
+    }
264
+
265
+    try {
266
+        // Try to read saved settings
267
+        var desc = app.getCustomOptions(appString);
268
+        mainDialog.outputName.text = desc.getString(outputNameKey);
269
+        mainDialog.destinationFolder.text = desc.getString(destinationKey);
270
+        mainDialog.rasterizeText.value = desc.getBoolean(rasterizeKey);
271
+        mainDialog.exportByGroup.value = desc.getBoolean(exportByGroupKey);
272
+        mainDialog.exportHidden.value = desc.getBoolean(exportHidden);
273
+        mainDialog.exportQML.value = desc.getBoolean(exportQML);
274
+    }
275
+    catch(e) {
276
+        // Default settings on first run
277
+        mainDialog.exportByGroup.value = true;
278
+        mainDialog.exportHidden.value = false;
279
+        mainDialog.exportQML.value = true;
280
+    } // Use defaults
281
+    
282
+    app.bringToFront();
283
+    mainDialog.defaultElement.active = true;
284
+    mainDialog.center();
285
+
286
+    var result = mainDialog.show();
287
+    if (cancelButton != result) {
288
+        var desc = new ActionDescriptor();
289
+        desc.putString(outputNameKey, mainDialog.outputName.text);
290
+        desc.putString(destinationKey, mainDialog.destinationFolder.text);
291
+        desc.putBoolean(rasterizeKey, mainDialog.rasterizeText.value);
292
+        desc.putBoolean(exportByGroupKey, mainDialog.exportByGroup.value);
293
+        desc.putBoolean(exportHidden, mainDialog.exportHidden.value);
294
+        desc.putBoolean(exportQML, mainDialog.exportQML.value);
295
+        app.putCustomOptions(appString, desc);
296
+    }
297
+    return result;
298
+}
299
+
300
+function countLayers(obj) {
301
+    // Even when grouping layers, we export all layers at depth == 0
302
+    for (var i = 0; i < obj.artLayers.length; i++) {
303
+       layerCount++;
304
+    }
305
+    for (var i = 0; i < obj.layerSets.length; i++) { // Recursive
306
+        if (!mainDialog.exportByGroup.value)
307
+            countLayers(obj.layerSets[i]);
308
+        layerCount++;
309
+    }
310
+}
311
+
312
+function hideAll(obj) {
313
+    for (var i = 0; i < obj.artLayers.length; i++) {
314
+        obj.artLayers[i].allLocked = false;
315
+        obj.artLayers[i].visible = false;
316
+    }
317
+    for (var i = 0; i < obj.layerSets.length; i++) { // Recursive
318
+        hideAll(obj.layerSets[i]);
319
+    }
320
+}
321
+
322
+function exportChildren(dupObj, orgObj, exportInfo, dupDocRef, fileNamePrefix) {
323
+     var exportQML = mainDialog.exportQML.value
324
+
325
+    // Track names to detect duplicates
326
+    var names = new Array;
327
+    var uniqueCounter = 1;
328
+
329
+    if (!mainDialog.exportByGroup.value)
330
+        hideAll(dupObj)
331
+    
332
+    for (var i = dupObj.layers.length - 1; i >= 0 && !cancelExport ; i--) {
333
+        progressPanel.myProgressBar.value = (layerIndex++)/layerCount
334
+        var currentLayer = dupObj.layers[i];
335
+        // Ensure unique layer names
336
+        while (names[currentLayer.name]) {
337
+            $.writeln("Warning: duplicate layer name: " + currentLayer.name); 
338
+            currentLayer.name = orgObj.layers[i].name+  "_#" + uniqueCounter++;
339
+        }
340
+        names[currentLayer.name] = true;
341
+
342
+        // Skip hidden layers
343
+        var visible = true;
344
+        if (!orgObj.layers[i].visible) {
345
+            visible = false   
346
+        }
347
+
348
+        if (!mainDialog.exportByGroup.value) {
349
+            // Ignore layer groups and only show one layer at once
350
+            if (currentLayer.typename== "LayerSet") 
351
+                continue;
352
+            dupObj.layers[i].visible = true
353
+        } else {
354
+            // Hide all but current layergroup
355
+            for (var k = dupObj.layers.length - 1; k >= 0; k--) 
356
+                dupObj.layers[k].visible = (k==i)
357
+        }
358
+           
359
+        if (!visible && !mainDialog.exportHidden.value)
360
+            continue;
361
+
362
+        // Since we already save opacity, we dont want it affecting the output image
363
+        var opacity = currentLayer.opacity / 100.0;
364
+        currentLayer.opacity = 100;
365
+
366
+        var layerName = dupObj.layers[i].name; // store layer name before change doc
367
+        var fileNameBody = layerName.toLowerCase();
368
+
369
+        // Ignore empty text layers
370
+        if (currentLayer.kind == LayerKind.TEXT && currentLayer.textItem.contents == "") continue;
371
+        var documentCopyTmp = dupDocRef.duplicate();
372
+
373
+        // Trim copied document to layer bounds
374
+        if (activeDocument.activeLayer.isBackgroundLayer == false) {
375
+            // app.activeDocument.trim(TrimType.TRANSPARENT); 
376
+            var bounds = currentLayer.bounds            
377
+            activeDocument.crop (bounds, 0, bounds.width, bounds.height)
378
+        }
379
+
380
+        fileNameBody = fileNameBody.replace(/[ :\/\\*\?\"\<\>\|#]/g, "_"); // '/\:*?"<>|' -> '_'
381
+        if (fileNameBody.length > 120) {
382
+            fileNameBody = fileNameBody.substring(0, 120);
383
+        }
384
+
385
+        var isText = (currentLayer.kind == LayerKind.TEXT && !(mainDialog.rasterizeText.value))
386
+        var filename = fileNameBody + ".png";
387
+        if (exportQML) {
388
+            // Write QML  properties
389
+            if (isText) qmlfile.write("    Text {\n");
390
+            else qmlfile.write("    Image {\n");
391
+            qmlfile.write("        id: " + fileNameBody + "\n");
392
+
393
+            if (!visible)
394
+                qmlfile.write("        visible: " + visible+ "\n");
395
+
396
+            var xoffset = currentLayer.bounds[0].as("px");
397
+            var yoffset = currentLayer.bounds[1].as("px");
398
+
399
+            if (isText) {
400
+                var textItem = currentLayer.textItem;
401
+                qmlfile.write("        text: \"" + textItem.contents + "\"\n");
402
+
403
+                // ### Temporary hack to set font positioning
404
+                // Using pointsize doesnt work for some reason and we need to
405
+                // figure out which metric we need to use ascending, perhaps?
406
+                yoffset -= textItem.size.as("px") / 4;
407
+
408
+                qmlfile.write("        font.pixelSize: " + Math.floor(textItem.size.as("px")) + "\n");
409
+
410
+                //var fontfamily = app.textFonts.getByName(textitem.font);
411
+                qmlfile.write("        font.family: \"" + textItem.font + "\"\n");
412
+
413
+                if (textItem.font.indexOf("Bold") != -1) qmlfile.write("        font.bold: true\n");
414
+
415
+                if (textItem.font.indexOf("Italic") != -1) qmlfile.write("        font.italic: true\n");
416
+                qmlfile.write("        color: " + qtColor(currentLayer.textItem.color) + "\n");
417
+                qmlfile.write("        smooth: true\n");
418
+            } else {
419
+                qmlfile.write("        source: \"images/" + filename + "\"\n");
420
+            }
421
+
422
+            qmlfile.write("        x: " + xoffset + "\n");
423
+            qmlfile.write("        y: " + yoffset + "\n");
424
+            qmlfile.write("        opacity: " + opacity + "\n");
425
+            qmlfile.write("    }\n");
426
+        }
427
+        // Save document
428
+        if (!isText) {
429
+            var saveFile = new File(exportInfo.destination + "/images/" + filename);
430
+            pngSaveOptions = new PNGSaveOptions();
431
+            pngSaveOptions.interlaced = false;
432
+            documentCopyTmp.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
433
+        }
434
+
435
+        // Close tempfile
436
+        documentCopyTmp.close(SaveOptions.DONOTSAVECHANGES);
437
+
438
+        if (!mainDialog.exportByGroup.value)
439
+            dupObj.layers[i].visible = false
440
+    }
441
+
442
+    for (var i = 0; i < dupObj.layerSets.length; i++) {
443
+        var fileNameBody = fileNamePrefix;
444
+        fileNameBody += "_" + "s";
445
+        if (!mainDialog.exportByGroup.value)
446
+            exportChildren(dupObj.layerSets[i], orgObj.layerSets[i], exportInfo, dupDocRef, fileNameBody); // recursive call
447
+    }
448
+}
449
+
450
+function collectLayerSets (theParent) {
451
+    if (!allLayerSets) {
452
+        var allLayerSets = new Array
453
+    }
454
+    for (var m = theParent.layers.length - 1; m >= 0;m--) {
455
+        var theLayer = theParent.layers[m];
456
+        // No need to process hidden layers
457
+        if (theLayer.typename == "LayerSet") {
458
+            allLayerSets = allLayerSets.concat(theLayer);
459
+            allLayerSets = allLayerSets.concat(collectLayerSets(theLayer))
460
+        }
461
+    }
462
+    return allLayerSets
463
+};

Loading…
Cancel
Save